* { box-sizing: border-box; }

/* The `hidden` attribute is only `display: none` in the user-agent stylesheet,
   so ANY author rule setting `display` on the same element silently defeats it
   — which is how the board's outcome dialog came to show the Lost reason
   selector on a Won close (#83): `.field` below sets `display: flex`.
   `!important` is required, not lazy: `[hidden]` and `.field` have equal
   specificity (0,1,0), so without it the winner is source order, which would
   work today and break the next time a `display` rule lands below this one. */
[hidden] { display: none !important; }

body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    font-size: 15px;
    line-height: 1.5;
    color: #1a1a1a;
    margin: 0;
    background: #fafafa;
}

a { color: #0066cc; }
a:hover { text-decoration: underline; }

a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
    outline: 2px solid #0066cc;
    outline-offset: 2px;
}

.skip-link {
    position: absolute;
    top: -100px;
    left: 0;
    background: #1a1a1a;
    color: #fff;
    padding: 0.5rem 1rem;
    z-index: 1000;
}
.skip-link:focus { top: 0; }

.site-header {
    background: #fff;
    border-bottom: 1px solid #ddd;
    padding: 0.75rem 1.5rem;
    display: flex;
    align-items: center;
    gap: 1.5rem;
    flex-wrap: wrap;
}

.site-brand a {
    font-weight: 600;
    text-decoration: none;
    color: #1a1a1a;
}

.site-nav ul {
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
}

.site-nav a {
    text-decoration: none;
}

.user-actions {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.user-display {
    color: #555;
    font-size: 0.9em;
}

.logout-form { display: inline; margin: 0; }

.logout-button {
    background: none;
    border: 1px solid #ccc;
    color: #1a1a1a;
    padding: 0.25rem 0.75rem;
    border-radius: 3px;
    cursor: pointer;
    font: inherit;
}
.logout-button:hover { background: #f0f0f0; }

main {
    padding: 1.5rem;
    max-width: 1200px;
    margin: 0 auto;
}

/* The Enquiries board opts out of the reading measure (#93). Six 200px columns
   need 1280px (#109 lowered the floor from 260px), so inside the 1152px content
   area five of six fit and the pipeline's two ends can never be on screen
   together. Board page only — every other template renders class="" and is
   unaffected. */
main.main-wide { max-width: none; }

h1, h2, h3 { margin-top: 0; }

.messages ul {
    list-style: none;
    margin: 1rem 1.5rem 0;
    padding: 0;
    max-width: 1200px;
}

.message {
    padding: 0.75rem 1rem;
    border-radius: 3px;
    margin-bottom: 0.5rem;
}
.message-success { background: #e6f4ea; color: #1e6f3f; }
.message-info    { background: #e7f1fb; color: #1c4f8a; }
.message-warning { background: #fff4d4; color: #7a5400; }
.message-error   { background: #fce4e4; color: #8a1c1c; }

table {
    border-collapse: collapse;
    width: 100%;
}
th, td {
    text-align: left;
    padding: 0.5rem 0.75rem;
    border-bottom: 1px solid #e0e0e0;
}
th { background: #f5f5f5; font-weight: 600; }

label { display: inline-block; margin-bottom: 0.25rem; }

input[type="text"],
input[type="number"],
input[type="email"],
input[type="date"],
input[type="datetime-local"],
input[type="password"],
input[type="url"],
select,
textarea {
    padding: 0.4rem 0.6rem;
    border: 1px solid #ccc;
    border-radius: 3px;
    font: inherit;
}

button.primary,
input[type="submit"] {
    padding: 0.5rem 1rem;
    background: #0066cc;
    color: #fff;
    border: 0;
    border-radius: 3px;
    cursor: pointer;
    font: inherit;
}
button.primary:hover,
input[type="submit"]:hover { background: #0052a3; }

ul.errorlist {
    list-style: none;
    margin: 0.25rem 0;
    padding: 0;
    color: #8a1c1c;
}

.signin-button {
    display: inline-block;
    padding: 0.5rem 1rem;
    background: #0066cc;
    color: #fff;
    text-decoration: none;
    border-radius: 3px;
}
.signin-button:hover {
    background: #0052a3;
    text-decoration: none;
}

/* ============================================================
   Reusable UI components (added Step 12).
   Tokens below name the existing palette so a colour pass is a
   single-place edit. Existing rules above intentionally keep
   their literal values to avoid touching Rolls/Inks/core.
   ============================================================ */
:root {
    --ground: #fafafa;
    --surface: #fff;
    --ink: #1a1a1a;
    --muted: #555;
    --faint: #777;
    --border: #e0e0e0;
    --border-strong: #ddd;
    --accent: #0066cc;
    --accent-hover: #0052a3;
    --accent-tint: #eef4fc;
    --ok-bg: #e6f4ea;
    --ok-fg: #1e6f3f;
    --hover: #f2f2f2;
    --radius: 3px;
    --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

/* Layout utilities */
.stack   { display: flex; flex-direction: column; gap: 1rem; }
.row     { display: flex; align-items: center; gap: 0.75rem; flex-wrap: wrap; }
.spread  { justify-content: space-between; }
.narrow  { max-width: 640px; }
.subhead { margin: 0; font-size: 1.15rem; }
.list-reset { list-style: none; margin: 0; padding: 0; }

/* Page header */
.page-header { margin-bottom: 1.5rem; }
.page-header .eyebrow {
    text-transform: uppercase; letter-spacing: 0.08em;
    font-size: 0.72rem; font-weight: 600; color: var(--faint); margin: 0 0 0.25rem;
}
.page-header h1 { font-size: 1.6rem; margin: 0; text-wrap: balance; }
.page-meta { margin-top: 0.5rem; color: var(--muted); font-size: 0.9rem; }

/* Cards */
.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.1rem 1.25rem;
}
.card h2, .card h3 { margin: 0 0 0.5rem; }
.card h2 { font-size: 1.15rem; }
.card h3 { font-size: 0.95rem; }
.card form + form { margin-top: 0.75rem; }
.card-grid { display: grid; gap: 1rem; }
.card-title { font-size: 1.05rem; font-weight: 600; }
.card-sub { color: var(--muted); font-size: 0.9rem; }
.card-highlight { border-left: 3px solid var(--accent); }

/* Key/value detail table */
.kv th { width: 38%; }

/* Chips — reuse the message palette. Two treatments share one box (#165
   ruling 1): a state chip fills it, the type chip outlines it. The border
   slot lives on .chip so the two sit at the same height side by side; a
   filled chip leaves it transparent and .chip-type leaves the background
   transparent instead. Structural rather than a colour rule — the chip's
   text is the identity — so a further card type needs no rule here. */
.chip {
    display: inline-flex; align-items: center; gap: 0.3rem;
    padding: 0.1rem 0.55rem; border-radius: 999px;
    border: 1px solid transparent;
    font-size: 0.72rem; font-weight: 600; letter-spacing: 0.03em;
    text-transform: uppercase; white-space: nowrap;
}
.chip::before {
    content: ""; width: 0.45rem; height: 0.45rem;
    border-radius: 50%; background: currentColor; opacity: 0.7;
}
.chip-neutral { background: #eef0f2; color: #5a636b; }
.chip-active  { background: #e7f1fb; color: #1c4f8a; }
.chip-done    { background: var(--ok-bg); color: var(--ok-fg); }
.chip-warning { background: #fff4d4; color: #7a5400; }
/* The type marker (#165): the one class an outlined chip wears. */
.chip-type    { background: transparent; border-color: currentColor; color: var(--muted); }

/* Buttons — including link-styled-as-button */
.btn, a.btn {
    display: inline-flex; align-items: center; gap: 0.4rem;
    padding: 0.45rem 0.9rem; border-radius: var(--radius);
    font: inherit; font-weight: 500; cursor: pointer; text-decoration: none;
    border: 1px solid var(--border-strong); background: var(--surface); color: var(--ink);
}
.btn:hover, a.btn:hover { background: var(--hover); text-decoration: none; }
.btn-primary, a.btn-primary { background: var(--accent); color: #fff; border-color: var(--accent); }
.btn-primary:hover, a.btn-primary:hover { background: var(--accent-hover); color: #fff; }
.btn-row { display: flex; gap: 0.6rem; flex-wrap: wrap; }
.btn[disabled] { opacity: 0.6; cursor: not-allowed; }

/* Flow stepper — the document lifecycle */
.stepper { display: flex; flex-wrap: wrap; gap: 0.4rem; list-style: none; margin: 0 0 1.5rem; padding: 0; }
.stepper li {
    display: flex; align-items: center; gap: 0.45rem;
    padding: 0.35rem 0.75rem; border-radius: var(--radius);
    font-size: 0.85rem; background: #f1f2f4; color: var(--faint);
}
.stepper .num {
    display: inline-flex; align-items: center; justify-content: center;
    width: 1.25rem; height: 1.25rem; border-radius: 50%;
    font-size: 0.72rem; font-weight: 600; background: #d9dde1; color: #fff;
}
.stepper .done { background: var(--ok-bg); color: var(--ok-fg); }
.stepper .done .num { background: var(--ok-fg); }
.stepper .current { background: var(--accent-tint); color: var(--accent-hover); font-weight: 600; }
.stepper .current .num { background: var(--accent); }

/* Questionnaire: chat transcript */
.chat-layout { display: grid; grid-template-columns: 1fr 260px; gap: 1.25rem; align-items: start; }
.transcript { display: flex; flex-direction: column; gap: 0.75rem; }
.msg { max-width: 78%; padding: 0.6rem 0.85rem; border-radius: 10px; }
.msg .who { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--faint); margin-bottom: 0.2rem; }
.msg-assistant { align-self: flex-start; background: #f1f3f5; border-bottom-left-radius: 2px; }
.msg-operator  { align-self: flex-end; background: var(--accent-tint); border-bottom-right-radius: 2px; }
.chat-input { margin-top: 1rem; display: flex; flex-direction: column; gap: 0.6rem; }
.chat-input textarea { width: 100%; min-height: 4.5rem; resize: vertical; }

/* Coverage sidebar */
.coverage { display: flex; flex-direction: column; gap: 0.5rem; }
.coverage li { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; font-size: 0.9rem; }

/* Monospace draft / preview panel */
.draft-panel {
    background: #f7f8f9; border: 1px solid var(--border); border-radius: var(--radius);
    padding: 1rem 1.1rem; font-family: var(--mono); font-size: 0.85rem; line-height: 1.55;
    white-space: pre-wrap; overflow-x: auto; margin: 0; color: #24292f;
}

/* Section review: two-column content + progress list */
.review-layout { display: grid; grid-template-columns: 240px 1fr; gap: 1.25rem; align-items: start; }
.section-list { display: flex; flex-direction: column; gap: 0.35rem; }
.section-list li a {
    display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
    padding: 0.5rem 0.7rem; border-radius: var(--radius); text-decoration: none;
    color: var(--ink); border: 1px solid transparent;
}
.section-list li a:hover { background: var(--hover); text-decoration: none; }
.section-list li a.current { background: var(--accent-tint); border-color: #cfe0f5; font-weight: 600; }
.section-list li .plain { padding: 0.5rem 0.7rem; display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }

/* Form field stacking */
.field { display: flex; flex-direction: column; gap: 0.25rem; margin-bottom: 0.9rem; }
.field label { font-weight: 500; margin: 0; }
.field input, .field textarea, .field select { width: 100%; }

/* Coming-soon disabled list */
.coming-soon { list-style: none; margin: 0.5rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.35rem; }
.coming-soon li {
    display: flex; align-items: center; justify-content: space-between;
    padding: 0.5rem 0.7rem; border: 1px dashed var(--border-strong); border-radius: var(--radius);
    color: var(--faint); font-size: 0.9rem;
}

/* Empty state */
.empty { text-align: center; color: var(--faint); padding: 2rem 1rem; border: 1px dashed var(--border-strong); border-radius: var(--radius); }

/* Feedback thread inside a section */
.feedback { display: flex; flex-direction: column; gap: 0.6rem; margin: 0.75rem 0; }
.feedback .turn { font-size: 0.9rem; }
.feedback .turn .lbl { font-weight: 600; }

/* Success receipt */
.receipt-icon {
    width: 2.5rem; height: 2.5rem; border-radius: 50%; background: #e6f4ea; color: #1e6f3f;
    display: inline-flex; align-items: center; justify-content: center; font-size: 1.3rem; font-weight: 700;
}

/* Accessible visually-hidden label (kept in the a11y tree) */
.visually-hidden {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden;
    white-space: nowrap;
}

/* Small button variant — compact card controls */
.btn-small, a.btn-small { padding: 0.3rem 0.6rem; font-size: 0.82rem; }

/* ============================================================
   Enquiries board (Sales) — a lightweight kanban.
   The column row is the ONLY horizontal-scroll container; the
   page body never scrolls sideways (PRD desktop/mobile NFR).
   ============================================================ */
.board {
    display: flex; gap: 1rem; align-items: flex-start;
    overflow-x: auto; padding-bottom: 0.75rem;
    /* position: relative is load-bearing (#117): it makes the board the
       containing block for absolutely positioned descendants — the cards'
       visually-hidden allocate labels — so their layout overflow lands in
       this scroll container instead of escaping its clip to the root
       element, where a card in a far column widens the page itself. */
    position: relative;
}
.board-column {
    flex: 1 0 200px; min-width: 0; max-width: 320px;
    background: var(--ground); border: 1px solid var(--border);
    border-radius: var(--radius); padding: 0.75rem;
}
.board-column-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 0.5rem; margin: 0 0 0.75rem; font-size: 0.95rem;
}
.board-column-count {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 1.5rem; padding: 0 0.4rem; border-radius: 999px;
    font-size: 0.72rem; font-weight: 600; background: #e4e7ea; color: var(--muted);
}
.board-column-body { display: flex; flex-direction: column; gap: 0.6rem; min-height: 2.5rem; }
.board-column-empty { color: var(--faint); font-size: 0.85rem; margin: 0.25rem 0; }
/* Sales renders the placeholder ALWAYS, so a column emptied by a drag shows it
   again with no JavaScript. The master board renders it only when the column
   is empty, so this rule does the opposite job there: it hides the stale
   placeholder a card DROPPED into an empty column now sits beside (#102 D7).
   One selector list rather than two rules, because the mechanism is the same
   and the two card families must not drift. */
.board-column-body:has(.enquiry-card) .board-column-empty,
.board-column-body:has(.work-item-card) .board-column-empty { display: none; }

/* The card box is shared with the master board's card (#147): same surface,
   border, radius, padding and column flow. Listed together rather than copied,
   so the two card families cannot drift. Everything below this rule is
   enquiry-specific. */
.enquiry-card,
.work-item-card {
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--radius); padding: 0.7rem 0.8rem;
    display: flex; flex-direction: column; gap: 0.5rem;
}
/* The card degrades by wrapping, with no breakpoint of any kind (#109). A flex
   container collects items into lines by each item's HYPOTHETICAL main size,
   then shrinks what is on each line, so `flex-wrap` degrades on max-content
   while `overflow-wrap` lowers the min-content floor shrinking cannot pass:
   wrap decides whether a row splits, breakability whether the split row fits.
   Both engage from the content, so a wide board is untouched and a ten-stage
   board (#103) needs no number revisited. The single "narrowest still-readable
   field" width is 7rem, used twice below and nowhere else. */
.enquiry-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem; flex-wrap: wrap; }
/* `flex: 1 1 7rem` is what keeps the head row a CARD-width rule: `flex-wrap`
   alone wraps whenever the name's max-content plus the value does not fit,
   which restyles wide cards that are fine today. The basis says "wrap when the
   name cannot keep 112px" instead. When the value does drop to its own line it
   lands at main-start, left-aligned under the name — `justify-content:
   space-between` places a lone item there, so no declaration is added for it. */
.enquiry-card-customer { font-weight: 600; text-decoration: none; color: var(--ink); flex: 1 1 7rem; overflow-wrap: anywhere; }
.enquiry-card-customer:hover { text-decoration: underline; }
.enquiry-card-value { font-size: 0.85rem; font-weight: 600; color: var(--muted); white-space: nowrap; }
/* `anywhere`, not `break-word`: only `anywhere` lowers the element's
   min-content size, which is the floor a flex item cannot shrink past.
   `break-word` breaks glyphs at paint time and leaves intrinsic size alone, so
   an unbreakable token would still push the row wide. Applied to the two
   free-text render targets only — `customer_name` above and
   `product_type_display` here, both CharField(max_length=255). */
.enquiry-card-product { margin: 0; font-size: 0.88rem; color: var(--muted); display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; overflow-wrap: anywhere; }
/* The dt labels are single unbreakable words ("RECEIVED" is 62px), so without
   the wrap the meta row escapes the card by 9.28px at a 200px column even with
   both free-text fields breakable. */
.enquiry-card-meta { margin: 0; display: flex; gap: 1rem; flex-wrap: wrap; }
.enquiry-card-meta div { display: flex; flex-direction: column; }
.enquiry-card-meta dt { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--faint); margin: 0; }
.enquiry-card-meta dd { margin: 0; font-size: 0.85rem; }
.enquiry-card-allocate { display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; }
/* `min-width: 7rem` replaces `min-width: 0`, which was dead weight: `flex: 1`
   gives the select a base size of ZERO, so its hypothetical main size is 0, the
   line never fills and the wrap above would be inert without this. The minimum
   raises it to 112px, which is what overflows the line and drops the button
   beneath at a narrow column. Safe only because the narrowest card content the
   board can produce is 146.41px — a future issue lowering the column floor
   below ~186px would turn this into an overflow (#109 risk 6). */
.enquiry-card-allocate select { flex: 1; min-width: 7rem; font-size: 0.82rem; padding: 0.3rem 0.4rem; }

/* Drag states (#71). board.js adds .is-draggable once SortableJS is wired, so
   the no-JS board keeps the default cursor — nothing there is draggable. */
.board.is-draggable .enquiry-card { cursor: grab; }
.enquiry-card.is-busy { opacity: 0.55; cursor: progress; }
.enquiry-card-ghost { opacity: 0.4; border-style: dashed; border-color: var(--accent); }

/* Modal dialogs: the Sales board's outcome dialog (Won / Lost) and the master
   board's move-refusal dialog (#102). One box for both, by selector list
   rather than by copy — the same reason the card box is shared below. A copy
   had already drifted by a `.card-sub` margin before this was merged. */
.outcome-dialog,
.move-refusal-dialog {
    width: min(28rem, calc(100vw - 2rem));
    border: 1px solid var(--border-strong); border-radius: var(--radius);
    background: var(--surface); color: var(--ink); padding: 1.25rem;
}
.outcome-dialog::backdrop,
.move-refusal-dialog::backdrop { background: rgb(26 26 26 / 45%); }
.outcome-dialog h2,
.move-refusal-dialog h2 { margin-bottom: 0.25rem; }
.outcome-dialog .card-sub,
.move-refusal-dialog .card-sub { margin: 0 0 1rem; }
.outcome-dialog .field:last-of-type { margin-bottom: 1.1rem; }
.field-hint { margin: 0; color: var(--faint); font-size: 0.82rem; }

/* ============================================================
   Enquiry detail (Sales) — the record beside its activity log.
   The .activity-* rules style WorkItemNote entries, a workitems concept,
   so they are not sales-owned despite living under this header.
   ============================================================ */
.detail-layout {
    display: grid; gap: 1rem; align-items: start;
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
}
.detail-text { margin: 0; overflow-wrap: anywhere; }
.activity-entry { border-left: 3px solid var(--border-strong); padding-left: 0.7rem; }
.activity-meta { margin: 0 0 0.15rem; font-size: 0.78rem; color: var(--faint); }

@media (max-width: 760px) {
    .chat-layout, .review-layout, .detail-layout { grid-template-columns: 1fr; }
}

/* ============================================================
   Master board (Overview) — #147, and #102's drag and refresh.
   Reuses the .board / .board-column / .board-column-head /
   -count / -body / -empty layout above, and shares the card box
   with .enquiry-card. New here: the filter row, the Waiting
   disclosure, the card's own text rules, and (since #102) the
   card's drag states and its refusal dialog.
   Read-only until #102; a card is now draggable and clickable.
   ============================================================ */
.board-filters {
    display: flex; gap: 1rem; align-items: flex-end; flex-wrap: wrap;
    margin-bottom: 1rem;
}
/* Only what differs from the shared .field: the row lays its controls out
   side by side, so the checkbox and its label sit on one line. */
.board-filters .field-inline {
    flex-direction: row; align-items: center; gap: 0.4rem;
}
.board-filters label { font-size: 0.82rem; color: var(--muted); }
.board-filters select { font-size: 0.85rem; padding: 0.3rem 0.4rem; }

.board-column-title { margin: 0; font-size: 0.95rem; font-weight: 600; }
/* The disclosure triangle is the only affordance telling a user the column
   opens, and a <summary> only draws it while it stays display: list-item. So
   the shared flex head goes on a wrapper INSIDE the summary rather than on the
   summary itself, and no rule here has to undo the shared one. */
.board-column-disclosure > summary { cursor: pointer; }

/* `anywhere`, not `break-word`, for the same reason .enquiry-card-customer
   gives above: only `anywhere` lowers the element's min-content size, which is
   the floor a flex item cannot shrink past. Every field on this card is free
   text or a name, so every one of them can carry an unbreakable token. */
.work-item-card-title { margin: 0; font-weight: 600; overflow-wrap: anywhere; }
.work-item-card-meta {
    margin: 0; display: flex; align-items: center; gap: 0.4rem;
    flex-wrap: wrap; font-size: 0.85rem; color: var(--muted);
    overflow-wrap: anywhere;
}
.work-item-card-owner {
    margin: 0; font-size: 0.85rem; color: var(--muted);
    overflow-wrap: anywhere;
}

/* The card title is a link to the card's detail page (#102 criterion 7). It
   reads as the card's own heading rather than as a link in a sentence: no
   underline at rest, the card's ink colour, and the underline on hover as the
   only affordance — exactly the treatment .enquiry-card-customer already gets
   for the same job, so the two boards' cards behave alike. */
.work-item-card-title a { color: inherit; text-decoration: none; }
.work-item-card-title a:hover { text-decoration: underline; }

/* Drag states (#102). board.js adds .is-draggable once SortableJS is wired, so
   a board with no scripting keeps the default cursor — nothing there is
   draggable. Deliberately the same three rules the enquiry card carries; the
   two are not merged into one selector list because .is-draggable is set by a
   different script on a different board, and a shared rule would suggest one
   switch turns both on. */
.board.is-draggable .work-item-card { cursor: grab; }
.work-item-card.is-busy { opacity: 0.55; cursor: progress; }
.work-item-card-ghost { opacity: 0.4; border-style: dashed; border-color: var(--accent); }

