* { box-sizing: border-box; }

/* ------------------------------------------------------------------
   NORTH ANCHOR SIGN CO. BRAND - colors and fonts from
   "01 Branding/Brand Quick Reference.txt". Every brand color is defined
   once here; change a value here and it changes everywhere.
     Midnight Navy  #0F1E33   Antique Brass #A5803F (on light)
     Light Gold     #C2A06A (on navy)   Warm Ivory #F7F5F0 (background)
     Ivory Text     #F4EFE6 (on navy)   Tagline Brown #7A5C2A
   Fonts: Marcellus (company name + headings), Jost (everything else).
   ------------------------------------------------------------------ */
/* Brand fonts served from this app's own static/fonts folder (no outside
   font service needed). Licenses: static/fonts/OFL-*.txt */
@font-face { font-family: "Marcellus"; src: url("../fonts/Marcellus-Regular.ttf") format("truetype"); font-weight: 400; font-display: swap; }
@font-face { font-family: "Jost"; src: url("../fonts/Jost-Regular.ttf") format("truetype"); font-weight: 100 449; font-display: swap; }
@font-face { font-family: "Jost"; src: url("../fonts/Jost-Medium.ttf") format("truetype"); font-weight: 450 549; font-display: swap; }
@font-face { font-family: "Jost"; src: url("../fonts/Jost-SemiBold.ttf") format("truetype"); font-weight: 550 900; font-display: swap; }

:root {
    --navy: #0F1E33;
    --navy-deep: #0B1727;
    --brass: #A5803F;
    --gold: #C2A06A;
    --ivory: #F7F5F0;
    --ivory-text: #F4EFE6;
    --brown: #7A5C2A;
    /* "accent" = the brand highlight color used by links, tabs, charts */
    --accent: #A5803F;
    --accent-dark: #7A5C2A;
    --accent-tint: #F2EBDD;
    --heading-font: "Marcellus", Georgia, "Times New Roman", serif;
    --body-font: "Jost", -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
}

/* Form controls don't inherit the page font by default in browsers. */
button, input, select, textarea { font-family: inherit; }

body {
    font-family: var(--body-font);
    margin: 0;
    background: var(--ivory);
    color: var(--navy);
    -webkit-font-smoothing: antialiased;
    font-variant-numeric: tabular-nums;
}

/* Headings and the app name use Marcellus (the logo's lettering style),
   in its one regular weight with a little extra letter spacing - never
   faux-bolded. Big dashboard numbers stay in Jost so they read cleanly. */
h1, h2, h3, .brand {
    font-family: var(--heading-font);
    font-weight: 400;
    letter-spacing: .03em;
}
.card .value {
    font-family: var(--body-font);
    font-weight: 600;
}
.topnav {
    background: linear-gradient(180deg, var(--navy) 0%, var(--navy-deep) 100%);
    border-bottom: 2px solid var(--brass);
    padding: 10px 24px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.18);
    position: sticky;
    top: 0;
    z-index: 20;
}
/* Top row: logo, data-profile badge, and (on narrow screens) the hamburger
   button. The link list itself lives in .nav-links below, so this row
   never gets crowded regardless of how many links the app has. */
.nav-bar {
    display: flex;
    align-items: center;
    gap: 14px;
}
/* The actual link list - a plain flex row on desktop/tablet; collapsed
   behind the hamburger button below 860px (see the media query at the
   bottom of this section). */
.nav-links {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
    margin-top: 8px;
}
.topnav a {
    color: #E2DACB;
    text-decoration: none;
    font-size: 14px;
    padding: 6px 4px;
    border-bottom: 2px solid transparent;
    transition: color .12s ease, border-color .12s ease;
}
.topnav a:hover { color: var(--ivory-text); border-color: var(--gold); }
.topnav .brand {
    font-weight: 700;
    font-size: 17px;
    color: #fff;
    display: flex;
    align-items: center;
    gap: 10px;
    border-bottom: none;
    letter-spacing: .01em;
}
/* North Anchor one-line logo (ivory + gold version, made for navy) sits
   straight on the navy bar - no white box behind it. */
.logo-chip { display: inline-flex; align-items: center; }
.logo-chip img { height: 40px; width: auto; display: block; }
.brand-app-name { font-size: 13px; letter-spacing: .18em; text-transform: uppercase; color: var(--gold); padding-left: 10px; border-left: 1px solid rgba(194,160,106,0.45); }

/* Which Data Profile (see database.py) is currently loaded - always visible
   in the nav so Test data and Live data never get mixed up by accident. */
.profile-badge {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    padding: 4px 9px;
    border-radius: 20px;
}
.profile-badge.profile-test { background: #78350f; color: #fde68a; }
.profile-badge.profile-live { background: #14532d; color: #bbf7d0; }

/* Hamburger menu button - hidden on desktop/tablet, shown only below the
   860px breakpoint (see media query below). Plain CSS bars, no icon font
   or image needed. */
.nav-toggle {
    display: none;
    margin-left: auto;
    background: transparent;
    border: 1px solid rgba(255,255,255,0.25);
    border-radius: 7px;
    padding: 7px 9px;
    cursor: pointer;
}
.nav-toggle-bar {
    display: block;
    width: 20px;
    height: 2px;
    background: #fff;
    border-radius: 2px;
}
.nav-toggle-bar + .nav-toggle-bar { margin-top: 4px; }

/* Grouped nav items ("Production", "Team", "Admin") - a button that reveals
   a small menu of related links, so the top-level nav stays short instead
   of listing every page flat. Opens on hover/keyboard-focus on desktop;
   on mobile it's a tap-to-expand accordion instead (see media query). */
.nav-dropdown { position: relative; }
.nav-dropdown-toggle {
    background: transparent;
    border: none;
    font-family: inherit;
    color: #cbd2e0;
    font-size: 14px;
    padding: 6px 4px;
    border-bottom: 2px solid transparent;
    cursor: pointer;
    transition: color .12s ease, border-color .12s ease;
}
.nav-dropdown-toggle:hover,
.nav-dropdown.open > .nav-dropdown-toggle { color: var(--ivory-text); border-color: var(--gold); }
.nav-caret { font-size: 10px; margin-left: 2px; position: relative; top: -1px; }

.nav-dropdown-menu {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    margin-top: 6px;
    background: #0F1E33;
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 8px;
    padding: 6px;
    min-width: 175px;
    box-shadow: 0 10px 24px rgba(0,0,0,0.35);
    z-index: 30;
}
.nav-dropdown-menu a {
    display: block;
    border-bottom: none;
    border-radius: 6px;
    padding: 8px 10px;
    white-space: nowrap;
}
.nav-dropdown-menu a:hover, .nav-dropdown-menu a:focus {
    color: #fff;
    background: rgba(255,255,255,0.08);
}
.nav-dropdown:hover > .nav-dropdown-menu,
.nav-dropdown:focus-within > .nav-dropdown-menu,
.nav-dropdown.open > .nav-dropdown-menu {
    display: block;
}

.nav-search { margin-left: auto; }
.nav-search input {
    background: rgba(255,255,255,0.1);
    border: 1px solid rgba(255,255,255,0.18);
    border-radius: 7px;
    padding: 6px 10px;
    color: #fff;
    font-size: 13px;
    width: 190px;
    transition: background .12s ease, width .15s ease;
}
.nav-search input::placeholder { color: #9aa3b5; }
.nav-search input:focus { background: rgba(255,255,255,0.16); outline: none; width: 230px; }

.nav-user-menu {
    margin-left: 12px;
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 13px;
    color: #6b7280;
}
.nav-user-menu a { font-size: 13px; }
.nav-user-role { color: #9ca3af; }

/* Hamburger collapse. Below this width the link list (.nav-links) hides
   behind the button and slides open as a full-width dropdown panel instead
   of wrapping into a wall of small links - that wrapping-flat-list look is
   exactly what made the nav feel cluttered on a phone/iPad before this. */
@media (max-width: 860px) {
    .nav-toggle { display: block; }
    .nav-links {
        display: none;
        flex-direction: column;
        align-items: stretch;
        gap: 2px;
        width: 100%;
    }
    .nav-links.open { display: flex; }
    .topnav a, .nav-dropdown-toggle {
        padding: 11px 6px;
        border-bottom: 1px solid rgba(255,255,255,0.08);
        text-align: left;
        width: 100%;
    }
    .nav-dropdown-toggle { display: flex; align-items: center; justify-content: space-between; }
    /* Touch screens have no hover, so on mobile a dropdown only opens via
       the explicit tap-to-toggle .open class (added by the small script in
       base.html) - hovering/focusing must NOT reveal it here, or a menu
       could get stuck open behind the collapsed panel. */
    .nav-dropdown:hover > .nav-dropdown-menu,
    .nav-dropdown:focus-within > .nav-dropdown-menu { display: none; }
    .nav-dropdown.open > .nav-dropdown-menu { display: block; }
    .nav-dropdown-menu {
        position: static;
        margin: 0 0 4px 12px;
        box-shadow: none;
        border: none;
        border-left: 2px solid rgba(255,255,255,0.15);
        border-radius: 0;
        background: rgba(255,255,255,0.03);
    }
    .nav-search { order: 99; width: 100%; margin: 10px 0 0; }
    .nav-search input { width: 100%; }
    .nav-search input:focus { width: 100%; }
    .nav-user-menu { margin: 12px 0 0; flex-wrap: wrap; }
}

.container { max-width: 1120px; margin: 0 auto; padding: 30px 20px 70px; }
/* Dashboard only: wider + shorter-padded container so more fits per row on
   a normal monitor without the rest of the app (forms, print docs) getting
   stretched out too. */
.container.container-wide { max-width: 1600px; padding: 14px 24px 18px; }

.flash {
    background: #eff6ff;
    border: 1px solid #bfdbfe;
    border-left: 4px solid #2563eb;
    padding: 12px 16px;
    border-radius: 8px;
    margin-bottom: 20px;
    color: #1e3a8a;
}
.flash p { margin: 2px 0; }

h1 { font-size: 25px; margin-bottom: 4px; letter-spacing: -.01em; color: #0F1E33; }
h2 { font-size: 17px; margin-top: 22px; color: #0F1E33; letter-spacing: -.005em; }

.dashboard-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 16px;
    margin-top: 20px;
}
.dashboard-grid.big { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 18px; }
.card {
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 12px;
    padding: 18px 20px;
    box-shadow: 0 1px 3px rgba(16,24,40,0.06);
    transition: box-shadow .15s ease;
}
.card.big { padding: 24px 26px; border-radius: 16px; box-shadow: 0 2px 8px rgba(16,24,40,0.08); position: relative; border-top: 3px solid var(--accent-tint); }
.card-link { display: block; text-decoration: none; color: inherit; transition: transform .12s ease, box-shadow .12s ease; cursor: pointer; }
.card-link:hover { transform: translateY(-3px); box-shadow: 0 10px 22px rgba(16,24,40,0.12); border-color: #D8C29A; }
.card-icon { font-size: 26px; margin-bottom: 8px; }
.card .label { font-size: 12px; color: #6b7280; text-transform: uppercase; letter-spacing: .06em; font-weight: 600; }
.card.big .label { font-size: 13px; }
.card .value { font-size: 28px; font-weight: 700; margin-top: 6px; color: #0F1E33; }
.card.big .value { font-size: 36px; margin-top: 8px; }
.card .sub { font-size: 13px; color: #6b7280; margin-top: 4px; }
.card.big .sub { font-size: 14px; margin-top: 6px; }
.card.warn .value { color: #b45309; }
.card.money .value { color: #047857; }

/* Dashboard hero cards - the handful of numbers meant to be seen first
   (Active Jobs, Won & Not Yet Collected, Bids Outstanding, New Bid
   Opportunities). Tinted with the brand accent and sized up from the
   regular .card.big below, so they read before the denser grid of
   everything else - see .dashboard-section-label + .dashboard-grid.big
   right after it in dashboard.html for that secondary grid. */
.dashboard-grid.hero { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 14px; margin-top: 14px; }
.card.hero {
    background: var(--accent-tint);
    border: none;
    border-radius: 14px;
    box-shadow: 0 3px 10px rgba(185,70,15,0.10);
}
.card.hero .card-icon { font-size: 24px; }
.card.hero .label { color: #9a5527; }
.card.hero .value { color: var(--accent-dark); }
.card.hero .sub { color: #a5714e; }
.card.hero.warn { background: #fef2f2; box-shadow: 0 3px 10px rgba(185,28,28,0.10); }
.card.hero.warn .value { color: #b91c1c; }
.card.hero.warn .label { color: #b45f5f; }
.card.hero.warn .sub { color: #b48080; }
.card.hero.money .value { color: var(--accent-dark); }
.card.hero.card-link:hover { box-shadow: 0 10px 20px rgba(185,70,15,0.18); border-color: transparent; }

.dashboard-section-label {
    margin: 22px 0 2px;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: #94a3b8;
}

/* Cash Collected by Month - a plain CSS bar chart (no charting library),
   fed by collected_by_month in the dashboard() route. Each column is a
   fixed-height "track" so every bar's baseline lines up regardless of its
   value, with the $ figure riding along the top of its own bar. */
.chart-box {
    background: #fff;
    border-radius: 14px;
    padding: 16px 20px 12px;
    box-shadow: 0 2px 8px rgba(16,24,40,0.06);
    margin-top: 16px;
}
.bar-chart { display: flex; align-items: flex-start; gap: 14px; margin-top: 8px; padding: 0 4px; }
.bar-chart-col { flex: 1; display: flex; flex-direction: column; align-items: center; min-width: 0; }
.bar-chart-track { height: 100px; width: 100%; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; }
.bar-chart-value { font-size: 11px; font-weight: 700; color: #374151; margin-bottom: 4px; white-space: nowrap; font-variant-numeric: tabular-nums; }
.bar-chart-bar { width: 100%; max-width: 46px; background: linear-gradient(180deg, var(--accent), var(--accent-dark)); border-radius: 5px 5px 0 0; min-height: 3px; }
.bar-chart-col:last-child .bar-chart-bar { background: linear-gradient(180deg, var(--accent-dark), #5E4520); }
.bar-chart-label { font-size: 10.5px; color: #6b7280; margin-top: 6px; white-space: nowrap; }

.stage-row { display: flex; align-items: center; gap: 14px; padding: 9px 0; }
.stage-name { width: 220px; font-size: 14px; color: #374151; flex-shrink: 0; font-weight: 500; }
.stage-bar-track { flex: 1; background: #eef0f4; border-radius: 6px; height: 15px; overflow: hidden; }
.stage-bar-fill { background: linear-gradient(90deg, var(--accent-dark), var(--accent)); height: 100%; border-radius: 6px; transition: width .3s ease; }
.stage-count { width: 32px; text-align: right; font-weight: 700; font-size: 14px; color: #0F1E33; }

/* Dashboard: a wider left/main column and a narrower right/sidebar column
   (e.g. Upcoming This Week + Recent Jobs on the left, Jobs by Stage on the
   right) - stacks to one column on narrow screens instead of squeezing. */
.dashboard-columns {
    display: grid;
    grid-template-columns: 2fr 1fr;
    gap: 14px;
    align-items: start;
    margin-top: 14px;
}
/* Grid columns default to a min-width that fits their widest content, which
   would otherwise let something wide inside (a table, a long unbroken word)
   push the column - and the whole page on a phone - wider than intended. */
.dashboard-columns > * { min-width: 0; }
@media (max-width: 860px) {
    .dashboard-columns { grid-template-columns: 1fr; }
}
/* Jobs by Stage reads tighter in the narrow sidebar than its full-width form */
.dashboard-col-narrow .stage-name { width: auto; font-size: 12.5px; }
.dashboard-col-narrow .stage-row { gap: 8px; }
.dashboard-col-narrow .stage-count { width: 24px; font-size: 13px; }

/* Month-to-Date vs Year-to-Date Profit & Loss, side by side */
.pl-compare { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px; margin-top: 10px; }
.pl-compare-col h3 { margin: 0 0 8px; font-size: 14px; color: #374151; }
.pl-line { display: flex; justify-content: space-between; padding: 5px 0; font-size: 14px; border-bottom: 1px solid #f3f4f6; }
.pl-line.total { font-weight: 700; border-bottom: none; border-top: 1px solid #e5e7eb; margin-top: 4px; padding-top: 8px; }
.pl-line .amt.profit-positive, .profit-positive { color: #047857; }
.pl-line .amt.profit-negative, .profit-negative { color: #b91c1c; }

/* Upcoming This Week list */
.upcoming-row { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-bottom: 1px solid #f3f4f6; font-size: 14px; }
.upcoming-row:last-child { border-bottom: none; }
.upcoming-date { width: 90px; flex-shrink: 0; font-weight: 600; color: #374151; font-size: 13px; }
.upcoming-type { flex-shrink: 0; }
.upcoming-detail { color: #6b7280; font-size: 13px; }
/* min-width:0 lets this shrink below its content's natural width instead of
   forcing the row (and the whole page, on a phone) wider than the screen -
   a long unbroken job number like "LakeJohannaFireDepatment-2025-001" would
   otherwise blow out the row's width. overflow-wrap lets that same long job
   number actually wrap onto a second line instead of overflowing sideways. */
.upcoming-main { flex: 1; min-width: 0; overflow-wrap: break-word; }

/* Groups related section-boxes together on longer pages (currently the Job
   page) so it reads as organized sections instead of one long undifferentiated
   scroll - purely a visual label between groups, doesn't change any layout. */
.group-divider {
    margin: 26px 0 6px;
    padding-top: 14px;
    border-top: 2px solid #dbe1ea;
    font-size: 13px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: #475569;
}
.dashboard-compact .group-divider { margin: 16px 0 2px; padding-top: 8px; font-size: 11.5px; }

/* Job Detail page tabs - see the script at the bottom of job_detail.html.
   Each button below corresponds to one .job-tab-panel (Financials, Team &
   Status, etc.), built automatically from the group-divider labels that
   used to just sit inline in the page. If JS never runs (disabled, or an
   error), #jobTabs stays empty (display:none via :empty) and every
   .group-divider + section renders in its old flat, always-visible order
   instead - the page still works, it's just the long-scroll version. */
.job-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin: 16px 0 4px;
    padding-bottom: 0;
    border-bottom: 2px solid #dbe1ea;
}
.job-tabs:empty { display: none; margin: 0; border: none; }
.job-tab {
    appearance: none;
    -webkit-appearance: none;
    border: none;
    background: transparent;
    padding: 8px 14px;
    font: inherit;
    font-size: 12.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: #64748b;
    cursor: pointer;
    border-radius: 7px 7px 0 0;
    border-bottom: 2px solid transparent;
    margin-bottom: -2px;
    white-space: nowrap;
}
.job-tab:hover { color: #0F1E33; background: #fff; }
.job-tab.active { color: var(--accent-dark); background: #fff; border-bottom-color: var(--accent); box-shadow: 0 -1px 4px rgba(16,24,40,0.06); }
.job-tab-panel[hidden] { display: none; }
@media print {
    .job-tabs { display: none; }
    .job-tab-panel[hidden] { display: block; }
}

/* ------------------------------------------------------------------
   Dashboard compact mode: a denser version of cards/sections/tables used
   ONLY on the Dashboard page (see .dashboard-compact wrapper), aimed at
   fitting everything on one screen on a normal monitor without scrolling.
   Boxes that could grow long over time (Upcoming, Recent Jobs) get their
   own internal scrollbar instead of pushing the page taller, so nothing
   is ever hidden - just scrolled to within its own compact box.
   ------------------------------------------------------------------ */
.dashboard-compact h1 { font-size: 20px; margin-bottom: 1px; }
.dashboard-compact .job-header { margin-bottom: 2px; }
.dashboard-compact h2 { font-size: 14px; margin-top: 10px; margin-bottom: 5px; }
.dashboard-compact .section-box { padding: 10px 14px; margin-top: 5px; }

.dashboard-compact .dashboard-grid.big { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 8px; margin-top: 8px; }
.dashboard-compact .card.big { padding: 9px 12px; border-radius: 9px; }
.dashboard-compact .card-icon { font-size: 16px; margin-bottom: 2px; }
.dashboard-compact .card.big .label { font-size: 10.5px; }
.dashboard-compact .card.big .value { font-size: 20px; margin-top: 2px; }
.dashboard-compact .card.big .sub { font-size: 11px; margin-top: 1px; }

.dashboard-compact .pl-compare { gap: 10px; margin-top: 6px; }
.dashboard-compact .pl-compare-col h3 { font-size: 12.5px; margin-bottom: 4px; }
.dashboard-compact .pl-line { padding: 3px 0; font-size: 12.5px; }
.dashboard-compact .pl-line.total { padding-top: 5px; margin-top: 2px; }
.dashboard-compact .pl-intro { font-size: 11.5px; margin: -4px 0 6px; }

.dashboard-compact .dashboard-columns { margin-top: 8px; gap: 10px; }
.dashboard-compact .upcoming-row { padding: 5px 0; font-size: 12.5px; }
.dashboard-compact .upcoming-date { width: 76px; font-size: 11.5px; }
.dashboard-compact .upcoming-detail { font-size: 11.5px; }
.dashboard-compact .scroll-box { max-height: 155px; overflow-y: auto; }
.dashboard-compact table { margin-top: 6px; }
.dashboard-compact th, .dashboard-compact td { padding: 5px 9px; font-size: 12.5px; }
.dashboard-compact .stage-row { padding: 4px 0; gap: 6px; }
.dashboard-compact .stage-bar-track { height: 11px; }
.dashboard-compact .stage-name { font-size: 11.5px; }
.dashboard-compact .stage-count { font-size: 12px; }

table { width: 100%; border-collapse: collapse; margin-top: 10px; background: #fff; border-radius: 10px; overflow: hidden; box-shadow: 0 1px 2px rgba(16,24,40,0.05); }
th, td { text-align: left; padding: 8px 11px; border-bottom: 1px solid #eef0f3; font-size: 14px; }
th { background: #f9fafb; font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em; color: #6b7280; font-weight: 700; }
tbody tr:nth-child(even) { background: #fbfbfc; }
tr:hover { background: #f3f6fb; }
a.rowlink { color: var(--accent-dark); text-decoration: none; font-weight: 600; }
a.rowlink:hover { text-decoration: underline; }

.btn {
    display: inline-block;
    background: var(--navy);
    color: var(--ivory-text);
    padding: 9px 16px;
    border-radius: 7px;
    text-decoration: none;
    font-size: 14px;
    font-weight: 600;
    border: none;
    cursor: pointer;
    box-shadow: 0 1px 2px rgba(15,30,51,0.3);
    transition: background .12s ease, transform .1s ease, box-shadow .12s ease;
}
.btn:hover { background: var(--accent-dark); color: #fff; transform: translateY(-1px); box-shadow: 0 4px 10px rgba(122,92,42,0.32); }
.btn:active { transform: translateY(0); }
.btn.secondary { background: #6b7280; box-shadow: 0 1px 2px rgba(107,114,128,0.2); }
.btn.secondary:hover { background: #4b5563; box-shadow: 0 4px 10px rgba(75,85,99,0.25); }
.btn:disabled { background: #d1d5db; color: #9ca3af; cursor: not-allowed; box-shadow: none; transform: none; }
.btn:disabled:hover { background: #d1d5db; transform: none; box-shadow: none; }

form.stacked label { display: block; margin-top: 14px; font-size: 14px; font-weight: 600; color: #374151; }
form.stacked input, form.stacked select, form.stacked textarea {
    width: 100%; padding: 8px 10px; margin-top: 4px; border: 1px solid #d1d5db; border-radius: 7px; font-size: 14px;
    transition: border-color .12s ease, box-shadow .12s ease;
}
form.stacked input:focus, form.stacked select:focus, form.stacked textarea:focus {
    outline: none; border-color: #C2A06A; box-shadow: 0 0 0 3px rgba(165,128,63,0.18);
}
form.stacked textarea { min-height: 70px; }
form.inline { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; margin-top: 10px; }
form.inline label { font-size: 12.5px; font-weight: 600; color: #374151; }
form.inline input, form.inline select { padding: 7px 9px; border: 1px solid #d1d5db; border-radius: 7px; }
form.inline input:focus, form.inline select:focus { outline: none; border-color: #C2A06A; box-shadow: 0 0 0 3px rgba(165,128,63,0.18); }

.badge { display: inline-block; padding: 3px 10px; border-radius: 999px; font-size: 12px; font-weight: 600; background: #E7EAF0; color: #0F1E33; }

/* Stage badge colors - purely visual, one per stage in the pipeline (see
   STAGE_BADGE_CLASSES in app.py for which stage gets which class - stage-bid,
   stage-won, stage-progress, stage-install, stage-complete, and stage-lost
   are also reused by a couple of unrelated badges elsewhere, so their colors
   stay put; everything else got its own new class below so stages that used
   to look identical (Design/Proofing, Approved, Permitting, Material
   Ordering, and Production all used to share one amber color) are now each
   their own color. */
.badge.stage-bid-invite { background: #E7EAF0; color: #0F1E33; }
.badge.stage-bid { background: #dbeafe; color: #1e40af; }
.badge.stage-won { background: #dcfce7; color: #166534; }
.badge.stage-design { background: #fae8ff; color: #86198f; }
.badge.stage-approved { background: #f3e8ff; color: #6b21a8; }
.badge.stage-permitting { background: #ffedd5; color: #9a3412; }
.badge.stage-material { background: #cffafe; color: #155e75; }
.badge.stage-progress { background: #fef3c7; color: #92400e; }
.badge.stage-install { background: #ede9fe; color: #5b21b6; }
.badge.stage-invoiced { background: #e0f2fe; color: #075985; }
.badge.stage-complete { background: #ccfbf1; color: #0f766e; }
.badge.stage-lost { background: #fee2e2; color: #991b1b; }
.badge.stage-archived { background: #e5e7eb; color: #4b5563; }

/* Stage legend on the Jobs list - a row of the same color-coded badges used
   in the table, each one also a link that filters to just that stage (see
   job_list.html / job_list() in app.py). */
.stage-legend { display: flex; flex-wrap: wrap; gap: 6px; margin: 14px 0 6px; }
.stage-legend .badge {
    text-decoration: none;
    cursor: pointer;
    transition: box-shadow .12s ease;
}
.stage-legend .badge:hover { box-shadow: 0 0 0 2px rgba(17,24,39,0.18); }
/* Active chip gets a ring in its own badge color, so it reads as "selected"
   without needing a second accent color. */
.stage-legend .badge.active { box-shadow: 0 0 0 2px currentColor; }
.stage-legend .badge.stage-legend-all { background: #f3f4f6; color: #374151; }
.stage-legend-count { opacity: .65; font-weight: 700; margin-left: 2px; }

/* Complete-but-still-owed alert - a Complete job that still has money owed
   on it, styled distinctly (deeper red) from the normal stage badges so it
   reads as "needs attention" rather than just another stage color. */
.badge-owed-alert { background: #dc2626; color: #fff; }
.badge-owed-note { display: inline-block; margin-left: 6px; font-size: 11px; font-weight: 700; color: #b91c1c; }
tr.row-owed-alert { background: #fef2f2; }
tr.row-owed-alert td { border-color: #fecaca; }

.section-box { background: #fff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 16px 18px; margin-top: 12px; box-shadow: 0 1px 2px rgba(16,24,40,0.05); }
.section-box h2 { margin-top: 0; }

/* Job page sections as collapsible <details>/<summary> boxes. They render
   open (class="section-box job-section" open) exactly like before on a
   normal screen - a small script at the bottom of job_detail.html removes
   the `open` attribute on phone-width screens only, so the very long job
   page starts collapsed to just its section titles there, and you tap one
   open to see it. Nothing changes on a normal-width screen. */
.job-section > summary.job-section-summary {
    font-size: 17px;
    margin: 0;
    color: #0F1E33;
    letter-spacing: -.005em;
    cursor: pointer;
    list-style: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    user-select: none;
}
.job-section > summary.job-section-summary::-webkit-details-marker { display: none; }
.job-section > summary.job-section-summary::after {
    content: "▾";
    font-size: 13px;
    color: #9ca3af;
    flex-shrink: 0;
    transition: transform 0.15s ease;
}
.job-section:not([open]) > summary.job-section-summary::after { transform: rotate(-90deg); }
.job-section[open] > summary.job-section-summary { margin-bottom: 4px; }
.job-header { display: flex; justify-content: space-between; align-items: baseline; flex-wrap: wrap; gap: 10px; }
.job-header .jobnum { font-family: "IBM Plex Mono", "SFMono-Regular", Consolas, monospace; font-weight: 600; background: var(--accent-tint); padding: 3px 9px; border-radius: 6px; color: var(--accent-dark); font-size: 15px; }

/* A job's site address, made tappable to open the phone's map/navigation
   app (Google Maps link - opens the native app on Android, and either the
   Google Maps app or a usable web map on iOS, without needing to detect
   which platform someone's on). Dashed underline instead of a normal link
   so it still reads as address text, not just another link in the list. */
.address-link { color: inherit; text-decoration: none; border-bottom: 1px dashed #9ca3af; }
.address-link:hover { color: var(--accent-dark); border-bottom-color: var(--accent-dark); }

/* A compact multi-column layout for the smaller job-page sections (Update
   Stage, Internal PM, Companies, Stage History, Notes) so they sit side by
   side instead of each taking a full-width row - same information, less
   scrolling. This uses CSS columns (a "waterfall" layout) rather than CSS
   grid on purpose: grid sizes an entire row to its tallest box, which left
   an awkward gap under any shorter box sharing a row with a taller one.
   Columns instead let each box stack directly under the next as soon as
   there's room, so short boxes don't leave dead space above the next row. */
.job-grid { column-width: 320px; column-gap: 12px; margin-top: 12px; }
.job-grid > .section-box {
    margin: 0 0 12px;
    break-inside: avoid;
    -webkit-column-break-inside: avoid;
}

/* Sections that are often empty (Permits, Site Visits, Outsourced/Material
   Orders, Change Orders) collapse down to one clickable line when there's
   nothing in them yet, instead of taking up a full section's worth of
   space - nothing is removed, it's all still one click away. */
summary.section-summary { cursor: pointer; color: var(--accent-dark); font-weight: 600; font-size: 14px; list-style: revert; }
summary.section-summary::marker { color: #9ca3af; }

.calendar-table { table-layout: fixed; }
.calendar-table th { text-align: center; }
.calendar-cell { vertical-align: top; height: 100px; padding: 6px !important; }
.calendar-cell-outside { background: #f9fafb; color: #c0c4cc; }
.calendar-cell-today { background: #eff6ff; }
.calendar-day-number { font-size: 12px; font-weight: 700; color: #6b7280; margin-bottom: 4px; }
.calendar-event {
    display: block;
    font-size: 11px;
    color: #fff;
    padding: 2px 5px;
    border-radius: 4px;
    margin-bottom: 3px;
    text-decoration: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.calendar-event:hover { opacity: 0.85; }

/* ---------------- Print / Install Sheet ---------------- */
/* The whole sheet always prints in portrait, EXCEPT each flagged plan/photo,
   which gets its own dedicated landscape page (see .print-landscape-page and
   the @page rules near the bottom of this file) - plans are almost always
   wider than tall, so this shows them as large/legible as possible instead
   of squeezed into a portrait-width column. This happens automatically when
   you print/Save as PDF - nothing to rotate or choose by hand. */
.print-doc {
    max-width: 780px;
    margin: 0 auto;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 10px;
    box-shadow: 0 1px 3px rgba(16,24,40,0.06);
    padding: 44px 48px;
}
.print-doc table { width: 100%; border-collapse: collapse; }
.print-doc table th {
    text-align: left;
    font-size: 11.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: #fff;
    background: #0F1E33;
    padding: 9px 12px;
}
.print-doc table td { padding: 8px 12px; border-bottom: 1px solid #eef0f4; font-size: 13.5px; color: #374151; }
.print-doc table tbody tr:nth-child(even) td { background: #f9fafb; }
/* Clean pagination for printed tables/panels - without this, a table row
   that happens to fall right at a page boundary gets sliced in half (half
   the row's text on one page, the rest on the next), which looks broken.
   break-inside:avoid on a row tells the browser "move this whole row to
   the next page rather than cutting it" - it only gives up and splits
   anyway if a single row is somehow taller than an entire page by itself.
   thead as table-header-group makes the column headers repeat at the top
   of every page a table spans, so page 2+ of a long table is still
   readable without scrolling back to page 1 to remember what a column means.
   NOTE: break-inside:avoid deliberately is NOT applied to .print-doc-panel
   itself - a panel can hold a table with dozens of rows, and telling the
   browser to keep that whole thing together just pushes the entire panel
   (table and all) onto the next page, leaving a mostly-blank page behind
   it. .print-stat is small and bounded (a handful of short lines) so it's
   safe to keep those together. */
.print-stat { break-inside: avoid; page-break-inside: avoid; }
.print-doc table tr, .bid-line-items tr { break-inside: avoid; page-break-inside: avoid; }
.print-doc table thead, .bid-line-items thead { display: table-header-group; }
.print-sheet-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: 20px;
    border-bottom: 2px solid var(--brass);
    padding-bottom: 20px;
    margin-bottom: 28px;
}
.print-sheet-title {
    font-family: var(--heading-font);
    font-size: 23px;
    font-weight: 400;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: #0F1E33;
    margin: 0 0 10px;
}
.print-sheet-header img { height: 64px; width: auto; flex-shrink: 0; }
.print-section { margin-top: 18px; }
.print-doc-panel {
    background: #f9fafb;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    padding: 16px 20px;
    margin-top: 18px;
}
.print-doc-panel h2 {
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: #6b7280;
    margin: 0 0 10px;
    /* Without this, a panel's title can land as the very last line on a
       page with its table pushed entirely to the next one - the title
       ends up orphaned by itself with nothing under it. This tells the
       browser not to break the page immediately after the heading, so
       it's pulled down to the next page together with (at least the
       start of) its own table instead. */
    break-after: avoid;
    page-break-after: avoid;
}
.print-doc-panel table { background: transparent; }
.print-doc-panel table th { background: #0F1E33; }
/* Each flagged file/page gets pushed onto its own fresh landscape page -
   "page: landscape" switches this box (and everything until the next forced
   break) to the named @page below; the very next section after it (there
   isn't one today, but just in case) would automatically fall back to the
   default portrait @page. */
.print-landscape-page {
    page: landscape;
    break-before: page;
    page-break-before: always;
    text-align: center;
}
.print-landscape-page .doc-label { font-weight: 700; font-size: 13px; margin-bottom: 6px; color: #0F1E33; text-align: left; }
/* max-height needs a fixed unit, not a percentage - percentages only work
   against an ancestor with an explicit height, and .print-landscape-page
   doesn't have one, so max-height:100% silently did nothing and let tall
   images overflow onto extra blank-ish pages instead of being capped to
   fit the one landscape page they were meant for. Landscape letter is
   ~11in x 8.5in; minus margins and room for the label above, 6.3in of
   vertical space reliably fits under the label.
   IMPORTANT: this image must NOT be display:block. Chromium has a print-
   pagination bug where a block-level image following another block-level
   sibling inside a named @page (like "landscape" below) gets shoved onto
   an extra blank page of its own. Leaving the image at its default inline
   display and centering it with text-align on the parent instead avoids
   that bug entirely - tested against an actual generated PDF. */
.print-landscape-page img { max-width: 9.5in; max-height: 6.3in; width: auto; height: auto; }

@page { size: portrait; margin: 0.6in; }
@page landscape { size: landscape; margin: 0.5in; }

/* ---------------- Formal Bid Document (client-facing) ---------------- */
/* A more formal, "professional invoice" look than the crew Install Sheet -
   logo sits in the upper right, matching how most invoices/bids are laid
   out, with a clear BID PROPOSAL title and bid number/date block on the left.
   Presented as a crisp white "sheet of paper" (card + shadow on screen, flat
   on the printed page) rather than sitting directly on the app's gray
   background, so it reads as a real document rather than another app page. */
.bid-doc {
    max-width: 760px;
    margin: 0 auto;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 10px;
    box-shadow: 0 1px 3px rgba(16,24,40,0.06);
    padding: 44px 48px;
}
.bid-print-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 20px;
    border-bottom: 2px solid var(--brass);
    padding-bottom: 20px;
    margin-bottom: 28px;
}
.bid-doc-title {
    font-family: var(--heading-font);
    font-size: 26px;
    font-weight: 400;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--navy);
    margin-bottom: 12px;
}
.bid-meta-table td { padding: 2px 0; font-size: 13px; }
.bid-meta-table td:first-child { color: #6b7280; padding-right: 18px; }
.bid-meta-table td:last-child { font-weight: 700; color: #0F1E33; letter-spacing: .01em; }
.bid-print-from { text-align: right; flex-shrink: 0; }
.bid-print-logo { height: 72px; width: auto; }
.bid-print-from-info { margin-top: 8px; font-size: 12.5px; color: #6b7280; line-height: 1.5; }
.bid-print-parties {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 30px;
    flex-wrap: wrap;
}
.bid-print-parties > div {
    flex: 1;
    min-width: 190px;
    background: var(--ivory);
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    padding: 14px 18px;
    break-inside: avoid;
    page-break-inside: avoid;
}
.bid-print-parties h3 {
    font-size: 11.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--brass);
    margin: 0 0 8px;
}
.bid-print-parties p { margin: 0; font-size: 14px; line-height: 1.55; color: #0F1E33; }
.bid-line-items { width: 100%; border-collapse: collapse; }
.bid-line-items th {
    text-align: left;
    font-size: 11.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--ivory-text);
    background: var(--navy);
    padding: 11px 14px;
}
.bid-line-items th:first-child { border-top-left-radius: 6px; }
.bid-line-items th:last-child { border-top-right-radius: 6px; }
.bid-line-items th:not(:first-child), .bid-line-items td:not(:first-child) { text-align: right; }
.bid-line-items tbody tr:nth-child(even) td { background: #f9fafb; }
.bid-line-items td { padding: 10px 14px; border-bottom: 1px solid #eef0f4; font-size: 14px; color: #374151; }
.bid-total-row td {
    font-weight: 800;
    font-size: 16.5px;
    color: #0F1E33;
    background: #F2EBDD !important;
    border-top: 2px solid var(--brass);
    border-bottom: none;
    padding-top: 12px;
    padding-bottom: 12px;
}
.bid-print-notes {
    margin-top: 26px;
    background: var(--ivory);
    border: 1px solid #E3D6BC;
    border-radius: 8px;
    padding: 14px 18px;
    break-inside: avoid;
    page-break-inside: avoid;
}
.bid-print-notes h3 {
    font-size: 11.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: #92400e;
    margin: 0 0 8px;
}
.bid-print-notes p { white-space: pre-wrap; font-size: 13.5px; color: #374151; line-height: 1.5; margin: 0 0 8px; }
.bid-print-notes p:last-child { margin-bottom: 0; }
.bid-print-footer {
    margin-top: 36px;
    padding-top: 16px;
    border-top: 1px solid #d1d5db;
    font-size: 12.5px;
    color: #6b7280;
    text-align: center;
    font-style: italic;
}

/* ---------------- Printable Reports (index page + the 6 report pages) ---------------- */
/* Reuses .print-doc/.print-doc-panel/.print-sheet-header from the Install
   Sheet above for the same look - these two classes are the report-specific
   extras: a row of summary numbers, and the highlighted total row some of
   the report tables end with. */
.print-stat-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    margin-top: 18px;
}
.print-stat {
    flex: 1;
    min-width: 150px;
    background: #f9fafb;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    padding: 14px 16px;
}
.print-stat .label {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: #6b7280;
    margin-bottom: 6px;
}
.print-stat .value { font-size: 20px; font-weight: 800; color: #0F1E33; }
.print-stat .sub { font-size: 12px; color: #9ca3af; margin-top: 2px; }
.print-doc table tr.total-row td {
    font-weight: 800;
    background: #F2EBDD !important;
    border-top: 2px solid var(--brass);
    border-bottom: none;
}

/* The Printable Reports menu (reports_print_index.html) isn't itself meant
   to be printed - it's a normal in-app page of links to the 6 report pages
   above, so it uses the app's regular card look rather than .print-doc. */
.print-report-links {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 14px;
    margin-top: 20px;
}
.print-report-link {
    display: block;
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 10px;
    padding: 18px 20px;
    text-decoration: none;
    transition: border-color .15s, box-shadow .15s;
}
.print-report-link:hover { border-color: #A5803F; box-shadow: 0 2px 8px rgba(165,128,63,0.12); }
.print-report-link .title { font-size: 15.5px; font-weight: 700; color: #0F1E33; margin-bottom: 4px; }
.print-report-link .desc { font-size: 13px; color: #6b7280; line-height: 1.5; }
@media (max-width: 700px) {
    .print-report-links { grid-template-columns: 1fr; }
}

/* General-purpose "only show this on a phone" / "hide this on a phone"
   pair, for content that should appear in a different spot (or not at all)
   on a narrow screen - e.g. a quick-access widget moved to the top of a
   page on mobile, with the full version staying in its normal place for
   everyone else. Only one of a matching mobile-only/hide-mobile pair is
   ever visible at once - see the 640px flip below. */
.mobile-only { display: none; }

/* ------------------------------------------------------------------
   Phone/narrow-screen pass. The app was built desktop-first, so this
   doesn't redesign anything - it just keeps every page usable (readable,
   scrollable instead of squished, tappable buttons) down to a phone-width
   screen, on top of all the desktop rules above.
   ------------------------------------------------------------------ */
@media (max-width: 640px) {
    .mobile-only { display: block; }
    .hide-mobile { display: none; }

    .container { padding: 16px 12px 50px; }
    .container.container-wide { padding: 10px 10px 14px; }

    .topnav { padding: 10px 12px; }
    .topnav .brand { font-size: 15px; }
    .topnav a, .nav-dropdown-toggle { font-size: 13px; }

    h1 { font-size: 20px; }
    h2 { font-size: 15.5px; }

    /* Wide tables (most of this app) would otherwise force the whole page
       to scroll sideways - instead only the table itself scrolls, so
       everything else stays put and readable. max-width is the important
       part: a table sitting inside a CSS grid/flex column (like the ones
       on the Dashboard) can otherwise grow past its column's width and
       drag the whole page wider with it, since grid/flex columns don't
       shrink their content below its natural size by default. */
    table { display: block; overflow-x: auto; white-space: nowrap; max-width: 100%; }
    thead, tbody, tr { display: table; width: 100%; table-layout: auto; }

    form.inline { flex-direction: column; align-items: stretch; gap: 8px; }
    form.inline > div { width: 100% !important; }
    form.inline input, form.inline select, form.inline textarea { width: 100% !important; }

    .dashboard-grid, .dashboard-grid.big { grid-template-columns: 1fr; }
    .pl-compare { grid-template-columns: 1fr; }
    .job-grid { grid-template-columns: 1fr !important; }

    .stage-row { flex-wrap: wrap; }
    .stage-name { width: auto; }

    /* Date + badge on their own line, job description on the next -
       reads much better in a narrow column than squeezing all three onto
       one line the way the desktop layout does. */
    .upcoming-row { flex-wrap: wrap; }
    .upcoming-main { flex-basis: 100%; }

    /* Jobs list: Site Address and the (usually blank) Legacy-badge column
       are the least useful columns to have on screen on a phone - hiding
       them lets Job #, Project, Stage, and Bid Amount fit without needing
       to scroll the table sideways at all. The full table (including
       address) is still there on a normal-width screen. */
    .table-jobs .col-address, .table-jobs .col-legacy { display: none; }

    .card.big .value { font-size: 26px; }
}

@media print {
    .no-print { display: none !important; }
    body { background: #fff; }
    .container { max-width: none; padding: 0; margin: 0; }
    .section-box, table { box-shadow: none; }
    a { color: inherit !important; text-decoration: none !important; }
    /* On real paper/PDF the page edge already frames the document, so drop
       the on-screen "card" styling (border/shadow/rounded corners) that
       exists only to separate the bid visually from the app around it. */
    .bid-doc { box-shadow: none; border: none; border-radius: 0; padding: 0; max-width: none; }
    /* Same fix as .bid-doc above - .print-doc (Install Sheet + all the
       printable Reports below) was still printing with its on-screen card
       border/shadow/rounded corners and 780px-cap padding, wasting paper
       margin and looking boxed-in on an actual printed page/PDF. */
    .print-doc { box-shadow: none; border: none; border-radius: 0; padding: 0; max-width: none; }
    /* Browsers normally strip background colors/images when printing unless
       the person happens to check "Background graphics" in the print dialog
       (off by default in most browsers) - which is why the bid header, the
       highlighted total row, the yellow notes box, and badges were printing
       as plain white/black instead of matching the on-screen preview. This
       forces those colors to print either way, so what you see IS what
       prints - no dialog option to remember to check. */
    * {
        -webkit-print-color-adjust: exact !important;
        print-color-adjust: exact !important;
        color-adjust: exact !important;
    }
}


/* Do Not Solicit (companies North Anchor agreed not to approach directly) */
.badge.badge-dns { background: #fee2e2; color: #991b1b; }
.dns-warning { margin: 12px 0; padding: 10px 14px; border-radius: 8px; background: #fef2f2;
    border: 1px solid #fecaca; border-left: 4px solid #b91c1c; color: #7f1d1d; font-size: 14px; }
.badge.badge-jobtype { background: var(--accent-tint); color: var(--brown); }
