/* FSVEXAN
   Application stylesheet.

   ============================================================================
   BRAND PALETTE — from the official FSVEXAN Brand Guidelines (page 04)
   ============================================================================
     BLUE        #0066CC      RED     #CC3333
     YELLOW      #FFCC00      GREEN   #009966
     CHARCOAL    #2D2D30      LIGHT GRAY #ECECEC      WHITE #FFFFFF

   Those seven values are the palette. The few extra steps below (mid greys,
   hover shades, tint backgrounds) are tints and shades of the official
   neutrals and hues — needed for borders, secondary text and accessible
   contrast — and are marked "derived". No non-brand hue is introduced.

   Interactive colour follows the app mockups on page 06 of the guidelines:
   the primary action is CHARCOAL, and BLUE carries links, focus and active
   state. RED / YELLOW / GREEN are reserved for status, never decoration.

   TYPOGRAPHY — Inter for everything (headlines, body, numbers, labels), in the
   CRM and the portal alike. Self-hosted from static/fonts/inter/ (the variable
   font, SIL Open Font License, see LICENSE.txt there): no Google Fonts request.
   Headlines 600-700, body 400; every number uses tabular figures so money and
   sizes line up in columns. Reading text is never under 14px (--text-sm); only
   small uppercase labels and badges use --text-label.
   ============================================================================ */

/* Inter, self-hosted (static/fonts/inter/): one variable file per script range covers every weight. */
@font-face { font-family: "Inter"; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url("../fonts/inter/inter-latin-wght-normal.8e433c0592f7.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url("../fonts/inter/inter-latin-ext-wght-normal.ad4eb06671be.woff2") format("woff2");
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }

:root {
  /* ---- OFFICIAL PALETTE ---- */
  --fsv-blue: #0066CC;
  --fsv-red: #CC3333;
  --fsv-yellow: #FFCC00;
  --fsv-green: #009966;
  --fsv-charcoal: #2D2D30;
  --fsv-light-gray: #ECECEC;
  --fsv-white: #FFFFFF;

  /* ---- roles ---- */
  --brand-ink: var(--fsv-charcoal);
  --brand-ink-2: #3C3C41;           /* derived: charcoal lightened, sidebar hover */
  --brand-text: var(--fsv-charcoal);
  --brand-muted: #6C6C70;           /* derived: charcoal + 30% white */
  --brand-muted-2: #9C9CA1;         /* derived: charcoal + 55% white */
  --brand-line: #DCDCDE;            /* derived: between light gray and charcoal */
  --brand-line-2: var(--fsv-light-gray);
  --brand-canvas: #F5F5F6;          /* derived: light gray lifted for page ground */
  --brand-surface: var(--fsv-white);

  --brand-accent: var(--fsv-blue);
  --brand-accent-dark: #0052A3;     /* derived: blue darkened for hover */
  --brand-accent-tint: #E6F0FA;     /* derived: blue at 10% */
  --brand-link: var(--fsv-blue);
  --brand-link-tint: #E6F0FA;

  --state-success: var(--fsv-green);
  --state-success-tint: #E5F5EF;    /* derived: green at 10% */
  --state-danger: var(--fsv-red);
  --state-danger-tint: #FAEBEB;     /* derived: red at 10% */
  --state-warning: var(--fsv-yellow);
  --state-warning-tint: #FFF6D9;    /* derived: yellow at 15% */
  --state-warning-text: #6B5200;    /* derived: yellow darkened to read on the tint */

  /* ---- TYPOGRAPHY ---- (Inter only; see the note at the top) */
  --font: "Inter", sans-serif;
  --font-display: var(--font);      /* headlines */
  --font-cond: var(--font);         /* figures and dates */

  --radius: 6px;

  /* ============================================================================
     DESIGN TOKENS — one set for the whole application (CRM, architect portal,
     sign-in pages). Colours stay as above; these are the shared measures.
     ============================================================================ */
  /* ---- layout: every page container is built from these two ---- */
  --page-max: 1600px;                       /* the widest page content ever gets */
  --page-gutter: clamp(1rem, 3vw, 2.5rem);  /* side spacing: 16px phone … 40px desktop */

  /* ---- spacing scale: gaps, padding and the vertical rhythm between blocks ---- */
  --space-xs: .25rem;
  --space-sm: .5rem;
  --space-md: 1rem;
  --space-lg: 1.5rem;
  --space-xl: 2rem;

  /* ---- type scale ----
     page title (h1) → section title (h2) → card title (h3) → body → secondary
     → labels / helper text. The page title shrinks smoothly on small screens. */
  --text-label: .78rem;    /* small uppercase labels and badges only — never reading text */
  --text-xs: .875rem;      /* helper text: 14px, the floor for anything read */
  --text-sm: .875rem;      /* secondary text, labels, buttons */
  --text-base: .9375rem;   /* body */
  --text-lg: 1.0625rem;    /* card titles */
  --text-xl: 1.1875rem;    /* section titles */
  --text-2xl: clamp(1.5rem, 1.2rem + .8vw, 1.875rem);  /* page titles */

  /* ---- shape ---- */
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 14px;
  /* Cards, panels and buttons are flat: their border is the edge (F44, 25 Oct 2026; was
     0 1px 2px). Floating layers — dropdowns, pop-ups, sticky bars — keep their own shadows. */
  --shadow-sm: none;
  --shadow-md: 0 4px 16px rgba(32, 33, 36, .07);

  /* ---- internal aliases: existing rules resolve through these ---- */
  --graphite: var(--brand-ink);
  --graphite-2: var(--brand-ink-2);
  --ink: var(--brand-text);
  --steel: var(--brand-muted);
  --steel-2: var(--brand-muted-2);
  --line: var(--brand-line);
  --line-2: var(--brand-line-2);
  --canvas: var(--brand-canvas);
  --surface: var(--brand-surface);
  --signal: var(--brand-accent);
  --signal-dark: var(--brand-accent-dark);
  --signal-tint: var(--brand-accent-tint);
  --blue: var(--brand-link);
  --blue-tint: var(--brand-link-tint);
  --green: var(--state-success);
  --green-tint: var(--state-success-tint);
  --red: var(--state-danger);
  --red-tint: var(--state-danger-tint);
  --amber: var(--state-warning-text);
  --amber-tint: var(--state-warning-tint);
}

/* ============================================================================
   ARCHITECT-FACING PALETTE — three fixed colours, defined once here.
   Applied to the architect portal (body.portal — templates/portal/base.html)
   and the sign-in pages (body.auth-page — accounts/_auth_layout.html). The
   staff CRM keeps the palette above; nothing below reaches it.

     Cloud Dancer #F0EEE7 — page ground, cards, fields, image frames
       (inspired by PANTONE 11-4201 Cloud Dancer; not an official conversion)
     Pale Sage    #E4EBE1 — the Home hero text panel, secondary panels,
       selected and highlighted states (a light tint inspired by PANTONE
       16-0421 Sage; not the exact swatch)
     Deep Ivy     #304B40 — text, headings, primary buttons, links, borders,
       icons, focus and active states (inspired by PANTONE 17-5912 TCX Dark
       Ivy; not an official conversion)

   Everything else is derived from these three (tints by mixing, borders and
   shadows by opacity). The one exception is the error state, which keeps its
   red so a validation message is never mistaken for ordinary text. The
   FSVEXAN logo artwork keeps its own colours.
   ============================================================================ */
:root {
  --fs-cloud-dancer: #F0EEE7;
  --fs-pale-sage: #E4EBE1;
  --fs-deep-ivy: #304B40;
}
body.portal, body.auth-page {
  --fs-ivy-strong: color-mix(in srgb, var(--fs-deep-ivy) 82%, #000);    /* hover / pressed */
  --fs-ivy-text-2: color-mix(in srgb, var(--fs-deep-ivy) 86%, var(--fs-cloud-dancer));  /* secondary text */
  --fs-ivy-muted: color-mix(in srgb, var(--fs-deep-ivy) 85%, var(--fs-cloud-dancer));   /* helper text, ≥4.5:1 on Cloud Dancer and Pale Sage */
  --fs-ivy-line: color-mix(in srgb, var(--fs-deep-ivy) 24%, var(--fs-cloud-dancer));    /* borders */
  --fs-ivy-line-soft: color-mix(in srgb, var(--fs-deep-ivy) 13%, var(--fs-cloud-dancer));
  --fs-sage-strong: color-mix(in srgb, var(--fs-pale-sage) 86%, var(--fs-deep-ivy)); /* selected on sage */

  /* The application's colour roles, re-pointed at the three colours. */
  --brand-ink: var(--fs-deep-ivy);
  --brand-ink-2: var(--fs-ivy-strong);
  --brand-text: var(--fs-deep-ivy);
  --brand-muted: var(--fs-ivy-muted);
  --brand-muted-2: var(--fs-ivy-muted);
  --brand-line: var(--fs-ivy-line);
  --brand-line-2: var(--fs-ivy-line-soft);
  --brand-canvas: var(--fs-cloud-dancer);
  --brand-surface: var(--fs-cloud-dancer);
  --brand-accent: var(--fs-deep-ivy);
  --brand-accent-dark: var(--fs-ivy-strong);
  --brand-accent-tint: var(--fs-pale-sage);
  --brand-link: var(--fs-deep-ivy);
  --brand-link-tint: var(--fs-pale-sage);
  --state-success: var(--fs-deep-ivy);
  --state-success-tint: var(--fs-pale-sage);
  --state-warning-text: var(--fs-deep-ivy);
  --state-warning-tint: var(--fs-pale-sage);
  --shadow-sm: none;   /* flat cards, as above (F44) */
  --shadow-md: 0 4px 16px rgba(48, 75, 64, .08);

  /* The aliases existing rules read (resolved at :root, so set here too). */
  --graphite: var(--brand-ink);
  --graphite-2: var(--brand-ink-2);
  --ink: var(--brand-text);
  --steel: var(--brand-muted);
  --steel-2: var(--brand-muted-2);
  --line: var(--brand-line);
  --line-2: var(--brand-line-2);
  --canvas: var(--brand-canvas);
  --surface: var(--brand-surface);
  --signal: var(--brand-accent);
  --signal-dark: var(--brand-accent-dark);
  --signal-tint: var(--brand-accent-tint);
  --blue: var(--brand-link);
  --blue-tint: var(--brand-link-tint);
  --green: var(--state-success);
  --green-tint: var(--state-success-tint);
  --amber: var(--state-warning-text);
  --amber-tint: var(--state-warning-tint);
}
/* A Pale Sage ring would vanish on Cloud Dancer: focused fields get a Deep Ivy one. */
body.auth-page .input:focus { box-shadow: 0 0 0 3px rgba(48, 75, 64, .28); }
body.auth-page .btn.primary { color: var(--fs-cloud-dancer); }

* { box-sizing: border-box; }
/* Any element carrying the `hidden` attribute must actually disappear, even
   when a class rule elsewhere (e.g. .btn's `display: inline-flex`) would
   otherwise tie or beat the browser's own [hidden] default. */
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; font-family: var(--font); font-size: 15px; font-weight: 400; line-height: 1.5; color: var(--ink);
  background: var(--canvas);
  /* Tabular figures everywhere: ₹ amounts, sizes and dates line up in columns. */
  font-variant-numeric: tabular-nums;
}
/* Form controls take the page's Inter too (browsers give them their own font otherwise). */
button, input, select, textarea { font-family: inherit; font-variant-numeric: inherit; }
a { color: var(--blue); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3, h4 { font-weight: 600; line-height: 1.25; margin: 0 0 .5rem; color: var(--graphite);
                 letter-spacing: -.011em; }
/* Headlines: Inter 700 for page titles, 600 for the rest (above). */
h1, .display { font-family: var(--font-display); font-weight: 700; letter-spacing: -.02em; }
h1 { font-size: var(--text-2xl); line-height: 1.15; }
h2 { font-size: var(--text-xl); }
h3 { font-size: 1.05rem; }
p { margin: 0 0 .75rem; }
small, .muted { color: var(--steel); }
.num { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }
:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

/* ---------- CRM shell ---------- */
.shell { display: grid; grid-template-columns: 232px 1fr; min-height: 100vh; }
.sidebar { background: var(--graphite); color: #cfd4da; padding: 1.25rem .75rem; position: sticky; top: 0; height: 100vh; overflow-y: auto; }

/* ---------- FSVEXAN lockup ----------
   The artwork is placed at its natural ratio (width:auto) — never stretched,
   rotated, recoloured or given effects. Clear space equals the height of the X
   mark, per page 03 of the guidelines: in the horizontal logo the X spans the
   full artwork height, in the stacked lockup it is 72% of it. */
.lockup { display: inline-block; line-height: 0; padding: var(--lockup-clear); }
.lockup-horizontal { --lockup-clear: var(--lockup-h); }
.lockup-stacked { --lockup-clear: calc(var(--lockup-h) * 0.72); }
/* height drives the size and width follows, so the ratio is always preserved.
   object-fit guarantees it even if a narrow container ever clamps the width:
   the logo letterboxes rather than squashing. */
.lockup-logo { display: block; height: calc(var(--lockup-h) * var(--logo-scale)); width: auto; max-width: 100%;
               object-fit: contain; object-position: left center; }
/* The wordmark (logo.svg) is wider for its height than the artwork these sizes were set for
   (12:1 against 7.7:1): at .8 of the height each placement is about a fifth wider than before,
   which keeps its fine letters legible without crowding the space around it. */
.lockup { --logo-scale: .8; }
/* "Stacked" placements show the same wordmark (the horizontal artwork, 60 units tall where the
   old stacked artwork was 81): the same height ratio keeps the mark exactly the size it always was. */
.lockup-stacked .lockup-logo { height: calc(var(--lockup-h) * 60 / 81 * var(--logo-scale)); }
/* The approved tagline, "Made to be seen.", always sits beneath the wordmark (partials/brand_lockup.html).
   Sized from the mark (about 38% of its height, never under 11px), set in the UI face at a medium
   weight with a hair of tracking, and left-aligned with the wordmark — clearly secondary to it. */
.lockup { --lockup-mark: var(--lockup-h); }
.lockup-stacked { --lockup-mark: calc(var(--lockup-h) * 60 / 81); }
.lockup-tagline { display: block; margin-top: max(4px, calc(var(--lockup-mark) * .2)); font-family: var(--font); font-weight: 500;
                  font-size: max(11px, calc(var(--lockup-mark) * .38)); line-height: 1.2; letter-spacing: .02em;
                  white-space: nowrap; }
.lockup-dark .lockup-tagline { color: var(--brand-ink); }
.lockup-light .lockup-tagline { color: #fff; }

/* Minimum sizes from page 03: primary logo 120px wide, icon 32px. */
.lockup-sm { --lockup-h: 22px; }
.lockup-md { --lockup-h: 30px; }
.lockup-lg { --lockup-h: 58px; }
.lockup-horizontal.lockup-sm .lockup-logo { min-width: 120px; }
.lockup-horizontal.lockup-md .lockup-logo { min-width: 120px; }

/* Type fallback, used only if the artwork files are missing. */
.lockup-rule { display: block; width: calc(var(--lockup-h) * 2.4); height: 3px;
               margin-bottom: calc(var(--lockup-h) * 0.28);
               background: linear-gradient(to right,
                 var(--fsv-blue) 0 25%, var(--fsv-red) 25% 50%,
                 var(--fsv-yellow) 50% 75%, var(--fsv-green) 75% 100%); }
.lockup-name { display: block; line-height: 1; font-family: var(--font); font-weight: 700;
               font-size: var(--lockup-h); letter-spacing: .13em; text-transform: uppercase; }
.lockup-dark .lockup-name { color: var(--brand-ink); }
.lockup-light .lockup-name { color: #fff; }

.brand { display: block; padding: 0 0 .5rem; color: #fff; }
.brand:hover { text-decoration: none; }
.nav-group { margin-bottom: 1rem; }
.nav-title { font-size: .78rem; color: var(--steel-2); padding: .25rem .6rem; }
.nav a { display: flex; justify-content: space-between; align-items: center; padding: .45rem .6rem; border-radius: var(--radius); color: #dfe3e7; }
.nav a:hover { background: var(--graphite-2); text-decoration: none; }
.nav a.active { background: var(--graphite-2); color: #fff; box-shadow: inset 3px 0 0 var(--signal); }
.nav .count { background: var(--signal); color: #fff; font-size: .75rem; border-radius: 10px; padding: 0 .45rem; font-weight: 600; }
.sidebar-foot { border-top: 1px solid var(--graphite-2); margin-top: 1rem; padding: 1rem .6rem 0; font-size: var(--text-sm); }
.sidebar-foot .who { color: #fff; }
/* The role under the name: light enough to read on the dark sidebar (about 7:1, was 2.6:1). */
.sidebar-foot .muted { color: #b4b8bf; }
.linkbtn { background: none; border: 0; padding: 0; color: #9fb4c9; cursor: pointer; font: inherit; }
.linkbtn:hover { text-decoration: underline; }
.main { min-width: 0; padding: var(--space-lg) var(--page-gutter) 3rem; }
.topbar { display: none; }

.page-head { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-end; justify-content: space-between; margin-bottom: 1.25rem; }
.page-head h1 { margin: 0; }
/* A heading with a small tag beside it (not inside it): crm/company_detail.html's tier. */
.title-row { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .6rem; }
.page-head .sub { color: var(--steel); margin-top: .2rem; }
.actions { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }

/* ---------- blocks ---------- */
/* One card language everywhere: hairline border, 8px corners, the faintest
   shadow — the portal's cards and the CRM's are the same object. */
.panel { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-md); padding: 1.1rem 1.25rem; margin-bottom: 1.25rem; box-shadow: var(--shadow-sm); }
.panel > h2:first-child, .panel > h3:first-child, .panel-head { margin-top: 0; }
.panel-head { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; margin-bottom: .75rem; }
.panel-head h2, .panel-head h3 { margin: 0; }
.panel.flush { padding: 0; }
.panel.flush .panel-head { padding: 1rem 1.25rem 0; }
.grid { display: grid; gap: 1.25rem; }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-main { grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr); }
.stack > * + * { margin-top: .75rem; }

.figures { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); margin-bottom: 1.25rem; box-shadow: var(--shadow-sm); overflow: hidden; }
.figure { padding: .9rem 1.1rem; border-right: 1px solid var(--line-2); }
.figure:last-child { border-right: 0; }
/* A figure's number is sized from its own cell's width (container units), so an amount
   like ₹1,98,134.00 fits its cell at every screen width instead of running into the next
   one; full size where there is room. A longer amount still wraps rather than overflows. */
.figure { min-width: 0; container-type: inline-size; }
.figure .value { font-family: var(--font-cond); font-size: clamp(1.05rem, 14cqi, 1.6rem); font-weight: 600; color: var(--graphite); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.figure .label { color: var(--steel); font-size: var(--text-sm); }
.figure.alert .value { color: var(--signal); }
/* No value to show (e.g. a firm never contacted): plain muted text at label size,
   so it doesn't read as a figure. It sits inside the full-size .value line, so the
   cell keeps the figures' height and its label lines up with the neighbours'. */
.figure .value .none { font-family: var(--font); font-size: var(--text-sm); font-weight: 500; color: var(--steel); }
/* The dashboard's six figures: rows that always divide evenly — 6 in a row,
   3 + 3 on tablets, 2 + 2 + 2 on phones (never 4 + 2). The 1px gap over the
   line colour draws the dividers between both columns and rows. */
.figures-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 1px; background: var(--line-2); }
.figures-6 .figure { border-right: 0; background: var(--surface); }
@media (max-width: 1100px) { .figures-6 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 560px) { .figures-6 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Five figures (company detail): one row, then 2 + 2 + 1 on phones with the
   last one across the full width — never a lone half-width cell. */
.figures-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 1px; background: var(--line-2); }
.figures-5 .figure { border-right: 0; background: var(--surface); }
@media (max-width: 560px) {
  .figures-5 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .figures-5 .figure:last-child { grid-column: 1 / -1; }
}

dl.facts { display: grid; grid-template-columns: max-content 1fr; gap: .35rem 1rem; margin: 0; }
dl.facts dt { color: var(--steel); }
dl.facts dd { margin: 0; overflow-wrap: anywhere; }

/* ---------- tables ---------- */
.table-wrap { overflow-x: auto; }
table.data { width: 100%; border-collapse: collapse; background: var(--surface); }
table.data th { text-align: left; font-weight: 600; color: var(--steel); font-size: .85rem; padding: .6rem .75rem; border-bottom: 1px solid var(--line); white-space: nowrap; }
table.data td { padding: .6rem .75rem; border-bottom: 1px solid var(--line-2); vertical-align: top; }
table.data tr:last-child td { border-bottom: 0; }
table.data tr:hover td { background: #fafbfc; }
table.data .right, .right { text-align: right; }
/* Codes and short dates read as one token — never "FS/QT/2026-" on one line
   and "27/0006" on the next. Inside .table-wrap the table scrolls instead. */
.nowrap, table.data td.nowrap { white-space: nowrap; }
table.data td.num, table.data th.num { text-align: right; font-variant-numeric: tabular-nums; }
/* .stack-sm: on a phone each row becomes a small card instead of a squeezed table row.
   The top line holds the row's name (td.stack-lead, after any td.stack-pre such as a
   tier badge) and its amount (td.stack-amount) on the right. Every other cell follows
   underneath across the full width, or side by side with its neighbours when marked
   td.stack-inline. A cell's data-label is shown in front of it; empty cells are left
   out. The column headings stay for screen readers. */
@media (max-width: 640px) {
  table.data.stack-sm, table.data.stack-sm tbody { display: block; }
  table.data.stack-sm thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  table.data.stack-sm tr {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: .25rem .6rem;
    padding: .7rem .75rem; border-bottom: 1px solid var(--line-2);
  }
  /* Ends the top line, whatever fits beside it. */
  table.data.stack-sm tr::before { content: ""; order: -1; flex-basis: 100%; margin-top: -.25rem; }
  table.data.stack-sm tr:last-child { border-bottom: 0; }
  table.data.stack-sm td { flex: 0 0 100%; min-width: 0; padding: 0; border: 0; }
  table.data.stack-sm td:empty { display: none; }
  table.data.stack-sm td.stack-pre { order: -4; flex: 0 0 auto; }
  table.data.stack-sm td.stack-lead { order: -3; flex: 1 1 0; font-weight: 600; }
  table.data.stack-sm td.stack-lead .muted { font-weight: 400; }
  table.data.stack-sm td.stack-amount { order: -2; flex: 0 0 auto; font-weight: 600; }
  table.data.stack-sm td.stack-inline { flex: 0 0 auto; }
  table.data.stack-sm td[data-label]::before { content: attr(data-label) " "; color: var(--steel); font-size: .8rem; }
  table.data.stack-sm tr:hover td { background: none; }
}
.empty { padding: 1.5rem 1.25rem; color: var(--steel); }

/* A small thumbnail inside a table row — CRM -> Portal Home's image list.
   contain, like every other view of these images: the whole picture stays
   recognisable at a glance instead of being centre-cropped to a square. */
.thumb-sm { width: 56px; height: 56px; object-fit: contain; border-radius: 4px; border: 1px solid var(--line); background: var(--line-2); display: block; }

/* Move up / Move down, stacked under a row's order number. */
.order-controls { display: inline-flex; flex-direction: column; gap: 2px; margin-top: .25rem; }
.order-controls form { margin: 0; }
.order-controls .btn { padding: 0 .4rem; min-height: 22px; line-height: 1; }

/* Sign-up — existing-firm suggestions under the "Firm / practice name" box
   (see static/js/firm-search.js). Shows only a firm's name, city and how
   many people are already associated with it: this is firm discovery, not a
   people directory.

   The panel FLOATS: it is positioned against .firm-picker, directly under
   the text box, and covers the fields below it while open instead of pushing
   them down — so opening, filtering or closing it moves nothing else on the
   page. It caps its own height (the script fits it to the room left on
   screen) and scrolls inside itself. */
.firm-picker { position: relative; }
.firm-suggestions {
  position: absolute; left: 0; right: 0; top: 100%; z-index: 30;
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface);
  max-height: 18rem; overflow-y: auto; overscroll-behavior: contain;
  box-shadow: 0 8px 20px rgba(32, 33, 36, .1);
}
.firm-suggestions-head {
  margin: 0; padding: .45rem .75rem; font-size: .72rem; font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--steel); border-bottom: 1px solid var(--line-2);
  position: sticky; top: 0; background: var(--surface); z-index: 1;
}
.firm-suggestions-head:empty { display: none; }
.firm-suggestion {
  display: flex; align-items: center; justify-content: space-between; gap: .75rem;
  padding: .55rem .75rem; border-bottom: 1px solid var(--line-2); cursor: pointer;
}
.firm-suggestion:last-child { border-bottom: 0; }
.firm-suggestion-about { min-width: 0; }
.firm-suggestion strong { display: block; overflow-wrap: anywhere; }
.firm-suggestion-meta { display: block; font-size: var(--text-sm); color: var(--steel); }
.firm-suggestion .firm-suggestion-use { flex: none; min-height: 34px; }
/* Keyboard / pointer highlight — the row Enter would pick. */
.firm-suggestion.is-active { background: var(--blue-tint); box-shadow: inset 3px 0 0 var(--blue); }
.firm-suggestions-note { margin: 0; padding: .6rem .75rem; font-size: var(--text-sm); color: var(--steel); }
.firm-suggestions-note.is-loading { font-style: italic; }
.firm-suggestions-empty { padding: .6rem .75rem .75rem; }
.firm-suggestions-empty .firm-suggestions-note { padding: 0 0 .2rem; color: var(--ink); font-weight: 600; }
.firm-suggestions-empty p + p { margin: 0 0 .55rem; font-size: var(--text-sm); color: var(--steel); }
/* The picked firm, or the decision to create a new one — compact, in flow,
   right under the field. */
.firm-chosen, .firm-new {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin: -.4rem 0 1rem;
  padding: .45rem .7rem; font-size: .9rem; border-radius: var(--radius);
}
.firm-chosen { background: var(--green-tint); border: 1px solid var(--green); }
.firm-new { background: var(--canvas); border: 1px solid var(--line); }
.firm-chosen[hidden], .firm-new[hidden] { display: none; }
.firm-chosen-tick {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; border-radius: 50%; background: var(--green); color: #fff; font-size: .7rem;
}
.firm-chosen-note { flex-basis: 100%; font-size: var(--text-sm); color: var(--steel); }
/* Tick, text and Change stay on one row; only the text wraps. */
.firm-chosen-text, .firm-new > span { flex: 1 1 0; min-width: 0; }
.firm-picker .linkbtn { margin-left: auto; color: var(--blue); font-weight: 600; }
/* Once a firm is picked (or a new one confirmed) the "practising independently?"
   hint has done its job; hiding it keeps the confirmation from pushing the form down. */
.firm-picker:has(.firm-chosen:not([hidden])) .help,
.firm-picker:has(.firm-new:not([hidden])) .help { display: none; }
/* "Did you mean..." — the server's answer when a typed name resembles an
   existing firm. The person picks one, or creates a new firm. */
.firm-match { margin: -.4rem 0 1rem; padding: .6rem .75rem; border: 1px solid var(--line); border-radius: var(--radius); }
.firm-match-list { list-style: none; margin: 0 0 .5rem; padding: 0; }
.firm-match-list li {
  display: flex; align-items: center; justify-content: space-between; gap: .75rem;
  padding: .35rem 0; border-bottom: 1px solid var(--line-2);
}
.firm-match-list li:last-child { border-bottom: 0; }

/* CRM -> Portal Home's add/edit preview box. It stands in for the panel
   these images actually appear in — the Wall Graphics card's own image
   area on the architect Home page (static/css/portal.css
   .product-feature-slides), which is roughly square on a desktop screen
   and a wider band once the card stacks on a phone. Same "contain"
   fitting as the real thing, so what staff approve here is what the
   architect sees, and nothing is ever cropped at either end. */
.portal-home-preview-box {
  position: relative; width: 230px; max-width: 100%; aspect-ratio: 1/1;
  border-radius: var(--radius); border: 1px solid var(--line); background: #E9E7E2;
  display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.portal-home-preview-box.new { border: 2px solid var(--brand-ink); }
.portal-home-preview-box img { width: 100%; height: 100%; object-fit: contain; }

/* ---------- badges ---------- */
.badge { display: inline-block; font-size: .78rem; font-weight: 600; padding: .1rem .5rem; border-radius: 4px; background: var(--line-2); color: var(--graphite); white-space: nowrap; }
.badge.blue { background: var(--blue-tint); color: var(--blue); }
/* Small text on a tint needs a deeper shade of the brand colour to reach 4.5:1
   (the same values the portal's badges use). */
.badge.green { background: var(--green-tint); color: #04794F; }
.badge.red { background: var(--red-tint); color: #A62828; }
.badge.amber { background: var(--state-warning-tint); color: var(--state-warning-text); }
/* The number beside a sidebar link when something is waiting there (CRM ->
   Material Sampling: requests still New). */
.nav-count { display: inline-block; min-width: 1.35rem; margin-left: .35rem; padding: 0 .4rem; border-radius: 999px; background: var(--state-warning-tint); color: var(--state-warning-text); font-size: .75rem; font-weight: 700; line-height: 1.35rem; text-align: center; }
.badge.orange { background: var(--signal-tint); color: var(--signal-dark); }
.tier { font-family: var(--font-cond); font-weight: 700; display: inline-grid; place-items: center; width: 1.5rem; height: 1.5rem; border: 1.5px solid var(--graphite); border-radius: 4px; font-size: var(--text-sm); }
.tier.A { background: var(--graphite); color: #fff; }

/* ---------- forms ---------- */
label { display: block; font-weight: 600; font-size: .9rem; margin-bottom: .3rem; color: var(--graphite); }
.field { margin-bottom: 1rem; }
.field .help { font-size: var(--text-sm); color: var(--steel); margin-top: .25rem; }
/* "Search cities" above a city list (static/js/city-filter.js). */
.city-filter { margin-bottom: .4rem; }
.city-filter-status { margin: 0 0 .4rem; font-size: .875rem; color: var(--steel); }
.city-filter-status:empty { display: none; }
/* Sign-up's City: one type-to-search box with a suggestions panel; the native
   <select> stays in the page, submitted, but out of sight. */
.city-combo { position: relative; }
.city-native-hidden { position: absolute !important; left: 0; top: 0; width: 1px !important; min-width: 0 !important; max-width: 1px !important; height: 1px !important; min-height: 0 !important; margin: 0 !important; padding: 0 !important; border: 0 !important; opacity: 0; overflow: hidden; pointer-events: none; clip-path: inset(50%); }
.city-combo-list {
  position: absolute; z-index: 30; top: calc(100% + 4px); left: 0; right: 0; max-height: 15rem; overflow-y: auto; margin: 0; padding: .25rem 0;
  list-style: none; background: #fff; border: 1px solid var(--line); border-radius: var(--radius); box-shadow: 0 6px 20px rgba(0,0,0,.12);
}
.city-combo-list[hidden] { display: none; }
.city-combo-option { padding: .5rem .75rem; cursor: pointer; font-size: .95rem; color: var(--ink); }
.city-combo-option:hover, .city-combo-option[aria-selected="true"] { background: var(--blue-tint); }
.city-combo-empty { padding: .5rem .75rem; font-size: .875rem; color: var(--steel); }
.field .error, .errorlist { color: var(--red); font-size: var(--text-sm); margin: .25rem 0 0; padding: 0; list-style: none; }
.input { width: 100%; font: inherit; color: var(--ink); background: #fff; border: 1px solid #c9ced5; border-radius: var(--radius); padding: .5rem .65rem; min-height: 40px; }
.input:focus { border-color: var(--blue); outline: none; box-shadow: 0 0 0 3px var(--blue-tint); }
textarea.input { min-height: 72px; resize: vertical; }
/* Sign-in, registration, password and public demo pages (.auth): 16px so iOS
   Safari doesn't zoom into a field on focus (the body text is 15px). */
.auth .input { font-size: 1rem; }
select.input { appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--steel) 50%), linear-gradient(135deg, var(--steel) 50%, transparent 50%); background-position: calc(100% - 16px) 55%, calc(100% - 11px) 55%; background-size: 5px 5px; background-repeat: no-repeat; padding-right: 2rem; }
.checkbox { width: 18px; height: 18px; accent-color: var(--signal); vertical-align: middle; margin-right: .4rem; }
.field-check label { display: flex; align-items: center; font-weight: 500; }
.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 1.25rem; }
.form-grid .wide { grid-column: 1 / -1; }
/* A small caps label grouping a long form into readable sections (e.g. the
   registration form) — quieter than a full h3, echoes .auth-eyebrow. */
.form-section {
  font-size: .78rem; font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  color: var(--steel); margin: 1.4rem 0 .5rem; padding-top: .9rem; border-top: 1px solid var(--line);
}
.form-section:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
/* A collapsible part of a form whose contents are usually filled for you
   (New quotation -> Architect / designer). */
.form-details { margin: 1rem 0 0; padding: .6rem .8rem; border: 1px solid var(--line); border-radius: var(--radius); }
.form-details > summary { cursor: pointer; }
.form-details[open] > summary { margin-bottom: .6rem; }
.inline-form { display: flex; gap: .5rem; flex-wrap: wrap; align-items: flex-end; }
.inline-form .field { margin: 0; }

/* ---------- Settings home cards ---------- */
.settings-card { display: block; text-decoration: none; color: inherit; transition: border-color .15s; }
/* In the Settings grid the gap does the spacing, so cards are 20px apart both ways (not 20 across, 40 down). */
.grid > .settings-card { margin-bottom: 0; }
.grid:has(> .settings-card) { margin-bottom: 1.25rem; }
.settings-card:hover { border-color: var(--signal); text-decoration: none; }
.settings-card h3 { margin: 0 0 .4rem; }
.settings-card p { margin: 0; }

/* ---------- search-select (type-to-search picker) ---------- */
.search-select { position: relative; }
.search-select-menu {
  position: absolute; z-index: 20; top: calc(100% + 4px); left: 0; right: 0; max-height: 260px; overflow-y: auto;
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius); box-shadow: 0 6px 20px rgba(0,0,0,.12);
}
.search-select-item { padding: .5rem .65rem; cursor: pointer; display: flex; flex-direction: column; gap: 1px; }
.search-select-item:hover, .search-select-item:focus, .search-select-item.is-active { background: var(--canvas); }
.search-select-item strong { font-size: .92rem; font-weight: 500; }
.search-select-item .muted { font-size: var(--text-sm); }
.search-select-item .search-select-detail { overflow-wrap: anywhere; }
.search-select-empty { padding: .6rem .65rem; font-size: var(--text-sm); }
.filters { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: 1rem; align-items: center; }
.filters .input { width: auto; min-width: 150px; }
.filters .search { min-width: 240px; flex: 1; max-width: 360px; }
/* A filter bar that folds on phones (crm/company_list.html, FIXES.md F29). On wider
   screens the wrapper disappears, so its fields sit in the bar exactly as before. */
.filters-more { display: contents; }
.filters .filters-toggle[hidden] { display: none; }
@media (min-width: 641px) { .filters .filters-toggle { display: none; } }
@media (max-width: 640px) {
  .filters-collapsible.filters-ready .search { min-width: 0; max-width: none; }
  .filters-collapsible.filters-ready .filters-more { display: none; }
  .filters-collapsible.filters-ready.filters-open .filters-more {
    display: flex; flex-wrap: wrap; gap: .5rem; width: 100%;
  }
  .filters-collapsible.filters-ready .filters-more .input { flex: 1 1 140px; min-width: 0; }
}

.btn { display: inline-flex; align-items: center; gap: .4rem; font: inherit; font-weight: 600; font-size: .92rem; padding: .5rem .95rem; min-height: 38px; border-radius: var(--radius); border: 1px solid #c9ced5; background: #fff; color: var(--graphite); cursor: pointer; white-space: nowrap; }
.btn:hover { background: var(--line-2); text-decoration: none; }
.btn.primary { background: var(--brand-ink); border-color: var(--brand-ink); color: #fff; }
.btn.primary:hover { background: var(--brand-ink-2); border-color: var(--brand-ink-2); }
.btn.dark { background: var(--graphite); border-color: var(--graphite); color: #fff; }
.btn.dark:hover { background: var(--graphite-2); }
.btn.danger { color: var(--red); border-color: #e9b9b4; }
.btn.small { padding: .25rem .6rem; min-height: 30px; font-size: var(--text-sm); }
.btn.ghost { border-color: transparent; background: transparent; }
.btn[disabled] { opacity: .5; cursor: not-allowed; }

.tabs { display: flex; gap: .25rem; border-bottom: 1px solid var(--line); margin-bottom: 1rem; flex-wrap: wrap; }
.tabs a { padding: .5rem .8rem; color: var(--steel); border-bottom: 2px solid transparent; margin-bottom: -1px; }
.tabs a.active { color: var(--graphite); border-color: var(--signal); font-weight: 600; }
.tabs a:hover { text-decoration: none; color: var(--graphite); }

/* ---------- messages ---------- */
.messages { list-style: none; padding: 0; margin: 0 0 1rem; }
.messages li { padding: .65rem .9rem; border-radius: var(--radius); margin-bottom: .5rem; border: 1px solid var(--line); background: #fff; border-left: 4px solid var(--blue); }
.messages li.success { border-left-color: var(--green); }
.messages li.error { border-left-color: var(--red); }
.messages li.warning { border-left-color: var(--amber); }
.test-banner { background: var(--state-warning-tint); color: var(--state-warning-text); border: 1px solid #EBD9A0; padding: .55rem .9rem; border-radius: var(--radius); margin-bottom: 1rem; font-size: .9rem; }
/* The list of what is still test data (crm/base.html), folded until asked for. */
.test-banner-list { margin-top: .35rem; }
.test-banner-list summary { cursor: pointer; font-weight: 600; }
.test-banner-list ul { margin: .4rem 0 0; padding-left: 1.2rem; }
.test-banner-list li { margin: .15rem 0; }
.test-banner-list a { color: inherit; font-weight: 600; }
.test-banner-list .muted { color: inherit; opacity: .8; }

/* ---------- timeline ---------- */
.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li { display: grid; grid-template-columns: 14px 1fr; gap: .75rem; padding: .55rem 0; border-bottom: 1px solid var(--line-2); }
.timeline li:last-child { border-bottom: 0; }
.timeline .dot { width: 10px; height: 10px; border-radius: 50%; margin-top: .45rem; background: var(--steel-2); }
.timeline .dot.INTERACTION { background: var(--signal); }
.timeline .dot.NOTE { background: var(--blue); }
.timeline .meta { font-size: var(--text-sm); color: var(--steel); }
.timeline .details { white-space: pre-line; font-size: .9rem; color: var(--ink); margin-top: .15rem; }

.task-row { display: flex; gap: .75rem; align-items: flex-start; padding: .6rem 0; border-bottom: 1px solid var(--line-2); }
.task-row:last-child { border-bottom: 0; }
.task-row .when { font-family: var(--font-cond); font-weight: 600; min-width: 64px; color: var(--steel); }
.task-row .when.overdue { color: var(--red); }
.task-row .body { flex: 1; min-width: 0; }

/* ---------- pipeline board ---------- */
/* The opportunity board: all six open stages fit side by side from about 1280px wide
   (columns go down to 150px); on narrower screens the board scrolls sideways in its own frame. */
.board { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(150px, 1fr); gap: .75rem; overflow-x: auto; padding-bottom: .5rem;
  align-items: start; }  /* each column only as tall as its cards */
.board-col { background: #e9ebee; border-radius: var(--radius); padding: .6rem; min-height: 200px; min-width: 0; }
.board-col h3 { font-size: .95rem; display: flex; flex-direction: column; gap: .1rem; margin: .1rem .2rem .6rem; }
.board-col-total { font-size: var(--text-sm); font-weight: 500; white-space: nowrap; }
/* The column's count and money total on its grey (#e9ebee): the muted grey only
   reached 4.38:1. The count is #4a4a4f (7.4:1) and the money is in the
   darkest ink at 600 (11.5:1), as on the dashboard pipeline, so the amounts read first. */
.board-col h3 .muted { color: #4a4a4f; }
.board-col h3 .board-col-total { color: var(--graphite); font-weight: 600; }
.board-card { display: block; background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: .6rem .7rem; margin-bottom: .5rem; color: var(--ink); }
.board-card:hover { border-color: var(--steel-2); text-decoration: none; }
.board-card .t { font-weight: 600; }
.board-card .s { font-size: var(--text-sm); color: var(--steel); }

/* Open pipeline on the dashboard: one flat surface — white stage cells split by
   hairlines (the 1px gap over the line colour), nothing nested inside a cell.
   The column count follows the panel's own width (stage-wrap is the container),
   so the six stages always sit 6, 3 + 3 or 2 + 2 + 2 and amounts fit. */
.stage-wrap { container-type: inline-size; }
.stage-bar { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 1px; background: var(--line-2);
  border: 1px solid var(--line-2); border-radius: var(--radius); overflow: hidden; }
.stage-bar > div { background: var(--surface); padding: .6rem .7rem; min-width: 0; }
@container (max-width: 760px) { .stage-bar { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@container (max-width: 330px) { .stage-bar { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.stage-bar .n { font-family: var(--font-cond); font-size: 1.3rem; font-weight: 600; color: var(--steel-2); }
.stage-bar .has .n { color: var(--graphite); }   /* stages with deals read first; empty ones stay light */
.stage-bar .l { font-size: var(--text-sm); color: #4a4a4f; }   /* stage names: about 8.5:1 on white */
/* Money in the pipeline: in the page's darkest ink and a heavier weight, so the amounts read first. */
.stage-bar .l.num { color: var(--graphite); font-weight: 600; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }

/* ---------- auth: sign in, create account, password reset ----------
   One layout for every public sign-in page (templates/accounts/_auth_layout.html).

   Wide screens: two structurally independent columns that always fill the
   full width. The page itself is exactly one screen tall and never scrolls.
   The hero is its own panel, laid out on its own — logo at the top, message
   in the space between, company name at the bottom — and the form is its own
   scroll area beside it. However long the form gets, whatever the firm
   results do, only the form column scrolls; nothing in it can reach the
   hero. The form column reserves its scrollbar's space from the start
   (scrollbar-gutter), so its content never shifts sideways either.

   Spacing, the logo and the headline scale with the screen height, so a
   short laptop screen tightens the hero instead of cutting anything off.

   Below 960px (where the hero would drop under ~500px wide) the page stacks:
   a compact hero — logo, eyebrow, headline — then the form, in normal flow. */
.auth { min-height: 100vh; display: grid; background: var(--surface); }
.auth-side {
  background: var(--canvas); color: var(--ink); display: flex; flex-direction: column; position: relative;
}
.auth-eyebrow {
  display: block; font-size: .78rem; font-weight: 600; letter-spacing: .13em; text-transform: uppercase;
  color: var(--blue); margin: 0 0 .6rem;
}
.auth-side h1 { color: var(--graphite); font-size: 2.3rem; }
.auth-lede { max-width: 40ch; color: var(--steel); font-size: 1.02rem; }
.auth-features { list-style: none; margin: 1.75rem 0 0; padding: 0; display: flex; flex-direction: column; gap: .7rem; }
.auth-features li { display: flex; align-items: flex-start; gap: .65rem; font-size: .92rem; color: var(--ink); }
.auth-features .dot { flex: none; width: 9px; height: 9px; border-radius: 50%; margin-top: .4rem; }
.auth-features .dot.blue { background: var(--blue); }
.auth-features .dot.green { background: var(--green); }
.auth-features .dot.yellow { background: var(--fsv-yellow); }
.auth-features .dot.red { background: var(--red); }
.auth-side-foot { display: flex; align-items: center; gap: .85rem; }
.auth-side-foot .rule { flex: none; width: 34px; height: 3px; background: var(--blue); border-radius: 2px; }
.auth-brand-link { display: inline-block; line-height: 0; cursor: pointer; text-decoration: none; }
.auth-brand-link:hover { text-decoration: none; }
.auth-brand-link:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; border-radius: 4px; }
.auth-form { background: var(--surface); display: flex; flex-direction: column; }
.auth-form h2 { font-size: 1.6rem; }
/* margin: auto centres the sign-in form in its column when there is room,
   and falls back to the top (never cut off) when there isn't. */
.auth-form-body { width: 100%; max-width: 25rem; margin: auto; }
.auth-register .auth-form-body { max-width: 34rem; margin: 0 auto auto; }
/* The line under the form's heading is reading copy: 16px, like the portal's. */
.auth-form-body > p.muted, .login-card > p.muted { font-size: 1rem; }
.auth-submit, .register-submit { width: 100%; justify-content: center; }
.register-submit { margin-top: 1rem; }
.auth-aside { margin-top: 1rem; }
.auth-switch { margin-top: 1.5rem; padding-top: 1.25rem; border-top: 1px solid var(--line); }
.register-signin { margin-top: 1rem; }
.status-step { margin: 1rem 0; padding: .85rem 1rem; border: 1px solid var(--line); border-radius: var(--radius); }
.status-step p { margin-top: 0; }
.status-rows { margin: 1.25rem 0 1rem; border-top: 1px solid var(--line); }
.status-rows .info-row { display: grid; grid-template-columns: 6rem minmax(0, 1fr); gap: .75rem; padding: .55rem 0; border-bottom: 1px solid var(--line-2); }
.status-rows dt { color: var(--steel); font-size: .88rem; }
.status-rows dd { margin: 0; overflow-wrap: anywhere; }

/* ---- the sign-in page ----
   Only templates/accounts/login.html carries .auth-login; Create your account
   and Password reset keep the plain hero above, so nothing here can reach
   them.

   The LEFT is a photograph (static/img/entry-photo.webp — the interior with the
   leaf wall graphic, no lettering in it) under a dark shade, with the lockup,
   the headline, the paragraph and the four benefits laid over it as real
   text. The photo is decoration only; every word is HTML.

   The RIGHT is live HTML: the message above the card, and the card itself. */
.auth-login {
  --entry-ink: #0A1218;   /* the photo's own dark edge, under the shade */
  --entry-display: var(--font);
}

/* The left: the photo fills the panel; the shade keeps the words on its dark side. */
.auth-login .auth-side { padding: 0; gap: 0; background: var(--entry-ink); color: #fff; position: relative; overflow: hidden; }
.auth-login .auth-side-main { position: relative; flex: 1 1 auto; display: flex; max-width: none; margin: 0; padding: 0; }
.auth-login .auth-side-foot { display: none; }
.auth-login .entry-art { position: absolute; inset: 0; display: block; }
.auth-login .entry-art img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 70% center; }
.auth-login .entry-art::after { content: ""; position: absolute; inset: 0;
  /* Shade only where the words sit (headline at the top left, benefits row at
     the bottom left); the rest of the photo stays at full brightness so the
     wall graphic reads. */
  background:
    radial-gradient(ellipse 62% 58% at 0% 22%, rgba(10, 18, 24, .62) 0%, rgba(10, 18, 24, .4) 55%, rgba(10, 18, 24, 0) 100%),
    radial-gradient(ellipse 62% 24% at 0% 100%, rgba(10, 18, 24, .7) 0%, rgba(10, 18, 24, .4) 55%, rgba(10, 18, 24, 0) 100%),
    linear-gradient(90deg, rgba(10, 18, 24, .2) 0%, rgba(10, 18, 24, 0) 55%); }
.auth-login .entry-copy {
  position: relative; z-index: 1; flex: 1 1 auto; display: flex; flex-direction: column; align-items: flex-start;
  padding: clamp(1rem, 4vh, 2.75rem) clamp(1.5rem, 4.4vw, 4rem) clamp(1.25rem, 4.5vh, 3rem);
}
.auth-login .entry-logo { margin: 0 0 clamp(.75rem, 4.5vh, 3.5rem); line-height: 0; }
.auth-login .entry-logo .lockup-lg { --lockup-h: clamp(28px, min(2.9vw, 5vh), 46px); padding: 0; }
.auth-login .entry-logo .lockup-horizontal.lockup-lg .lockup-logo { min-width: 0; }
/* Every word on the sign-in page is at least 14px, the logo's tagline included. */
.auth-login .entry-logo .lockup-tagline { font-size: max(.875rem, calc(var(--lockup-mark) * .38)); }
.auth-login .entry-eyebrow {
  margin: 0 0 clamp(.5rem, 1.6vh, 1rem); font-size: clamp(.875rem, min(1.05vw, 2vh), 1.1rem); font-weight: 600; letter-spacing: .14em; text-transform: uppercase;
  color: #9FD8F5;
}
.auth-login .entry-headline {
  margin: 0; font-family: var(--entry-display); font-weight: 900; line-height: .92; letter-spacing: -.035em; color: #fff;
  text-shadow: 0 2px 28px rgba(10, 18, 24, .45);  /* keeps the letters crisp where they cross the lit wall */
  font-size: clamp(2.75rem, min(8.3vw, 17.5vh), 10.5rem);
}
.auth-login .entry-headline-top { display: block; text-transform: uppercase; }
.auth-login .entry-headline-grad {
  display: block; width: fit-content; margin-top: .04em; padding: 0 .04em .22em 0; margin-bottom: -.12em; font-size: .8em; line-height: 1; letter-spacing: -.03em;
  background: linear-gradient(90deg, #35C9BD 0%, #6CC3F2 45%, #9CCBFF 100%); -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: #6CC3F2;
  /* a text-shadow would show through the see-through letters; a drop shadow sits behind them */
  text-shadow: none; filter: drop-shadow(0 2px 14px rgba(10, 18, 24, .45));
}
@media (forced-colors: active) {
  .auth-login .entry-headline-grad { background: none; -webkit-text-fill-color: currentColor; color: CanvasText; }
}
.auth-login .entry-rule { display: block; width: 3.5rem; height: 4px; margin: clamp(.9rem, 2.6vh, 1.6rem) 0; border-radius: 2px; background: #4FB3F0; }
.auth-login .entry-lede { text-shadow: 0 1px 12px rgba(10, 18, 24, .5); max-width: 36ch; margin: 0; font-size: clamp(1rem, min(1.35vw, 2.7vh), 1.45rem); line-height: 1.45; color: rgba(255, 255, 255, .92); }
.auth-login .entry-benefits {
  list-style: none; margin: auto 0 0; padding: clamp(1rem, 3vh, 2.5rem) 0 0; display: grid; grid-template-columns: repeat(4, auto);
  justify-content: start;
}
.auth-login .entry-benefits li {
  display: flex; flex-direction: column; gap: .15rem; padding: 0 clamp(.9rem, 1.9vw, 2rem);
  border-left: 1px solid rgba(255, 255, 255, .22);
}
.auth-login .entry-benefits li:first-child { padding-left: 0; border-left: 0; }
.auth-login .entry-benefits strong { font-size: clamp(1rem, min(1.3vw, 2.5vh), 1.4rem); font-weight: 700; color: #fff; }
.auth-login .entry-benefits span { font-size: clamp(.875rem, min(1vw, 1.95vh), 1.1rem); color: rgba(255, 255, 255, .85); }
.auth-login .entry-icon {
  width: clamp(34px, min(3.2vw, 6vh), 56px); height: clamp(34px, min(3.2vw, 6vh), 56px); margin-bottom: .55rem; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.auth-login .entry-icon text { fill: currentColor; stroke: none; font: 700 5.5px var(--font); }
.auth-login .entry-icon.blue { color: #4FA3F7; }
.auth-login .entry-icon.green { color: #34C77B; }
.auth-login .entry-icon.amber { color: #F5B638; }
.auth-login .entry-icon.red { color: #F2685A; }

/* The right: the message above the card, on a clean light ground. */
.auth-login .auth-form { background: var(--fs-cloud-dancer); }
/* The message and the card share one column, so their left and right edges line up. */
.auth-login .auth-form-body { width: min(100%, 26rem); max-width: none; margin: 0 auto auto; }
.auth-login .entry-message { margin: 0 0 clamp(1rem, 3.4vh, 2.25rem); color: var(--fs-deep-ivy); line-height: 1; }
.auth-login .entry-message-top {
  display: block; font-family: var(--entry-display); font-weight: 800; text-transform: uppercase; line-height: .98; letter-spacing: -.02em;
  font-size: clamp(2.2rem, min(3.9vw, 6.4vh), 4.4rem); color: var(--fs-deep-ivy);
}
.auth-login .entry-message-grad {
  display: block; width: fit-content; max-width: 100%; padding-bottom: .1em; margin-top: .04em;
  font-family: var(--font); font-weight: 800; font-size: clamp(1.4rem, min(2.5vw, 4.1vh), 2.8rem); line-height: 1.1; letter-spacing: -.015em;
  color: var(--fs-deep-ivy);
}
@media (forced-colors: active) {
  .auth-login .entry-message-grad { background: none; -webkit-text-fill-color: currentColor; color: CanvasText; }
}
.auth-login .login-card {
  /* Flat, one thin border — like every other card (FIXES.md F36). */
  max-width: none; margin-inline: 0; background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  padding: clamp(1.15rem, 2.6vh, 2rem) clamp(1.25rem, 2vw, 2rem);
}
/* "Sign in" heads the card (the page's h1 is the headline on the left), set
   in the same type the card's heading always had. */
.auth-login .login-card h2 {
  margin: 0 0 .5rem; font-family: var(--font); font-size: 1.6rem; font-weight: 600; line-height: 1.25; letter-spacing: -.011em;
  color: var(--graphite);
}
.auth-login .login-card .auth-switch { margin-bottom: 0; }

/* The third thing on the card (WhatsApp chat), and it looks like it. The filled
   Sign in button leads, Create your account follows as a link, and this sits
   below a hairline in muted text with an outlined button that never fills the
   width — so the order reads down the card without anything competing. */
.auth-login .login-demo { margin-top: 1.25rem; padding-top: 1.25rem; border-top: 1px solid var(--line-2); }
.auth-login .login-demo-title { margin: 0; font-size: .92rem; font-weight: 600; }
.auth-login .login-demo-note { margin: .2rem 0 .8rem; font-size: var(--text-sm); }
.auth-login .login-demo-btn { color: var(--steel); }
.auth-login .login-demo-btn:hover { color: var(--graphite); }
/* The WhatsApp chat in that spot: the same quiet outlined button, with the green
   WhatsApp mark so it is recognised at a glance. */
.auth-login .login-wa-btn { display: inline-flex; align-items: center; gap: .5rem; color: var(--graphite); }
.auth-login .login-wa-btn svg { width: 20px; height: 20px; flex: none; color: #25D366; }
.auth-login .login-wa-btn:hover { border-color: #25D366; }

@media (min-width: 960px) {
  .auth.auth-login { grid-template-columns: minmax(0, 58fr) minmax(0, 42fr); }
  .auth-login .auth-form { border-left: none; padding: clamp(2rem, 7vh, 5rem) clamp(1.5rem, 3.8vw, 3.75rem) clamp(.75rem, 1.5vh, 1.25rem); }
}
/* Large screens: a wider column, so the bigger message keeps to its three lines. */
@media (min-width: 1600px) {
  .auth-login .auth-form-body { width: min(100%, 30rem); }
}
/* A laptop-sized screen (up to about 960px tall): the right drawn tighter, so it
   still lands in one screenful — a slimmer card with "Book a demo" beside its
   note, and a quieter legal footer. */
@media (min-width: 960px) and (max-height: 959px) {
  .auth-login .auth-form { padding-top: clamp(1.75rem, 5.5vh, 3rem); padding-bottom: .5rem; }
  .auth-login .entry-message { margin-bottom: clamp(.75rem, 2.2vh, 1.5rem); }
  .auth-login .login-card { padding-block: .8rem; }
  .auth-login .login-card h2 { margin-bottom: .15rem; font-size: 1.4rem; }
  .auth-login .login-card > .muted { margin-bottom: .5rem; font-size: var(--text-sm); }
  .auth-login .login-card .field { margin-bottom: .4rem; }
  .auth-login .login-card .input { min-height: 40px; }
  .auth-login .auth-aside { margin-top: .55rem; }
  .auth-login .auth-switch { margin-top: .8rem; padding-top: .7rem; }
  .auth-login .login-demo {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: .75rem; align-items: center;
    margin-top: .7rem; padding-top: .7rem;
  }
  .auth-login .login-demo-title { grid-column: 1; font-size: var(--text-sm); }
  .auth-login .login-demo-note { grid-column: 1; margin: .1rem 0 0; font-size: var(--text-sm); }
  .auth-login .login-demo-btn { grid-column: 2; grid-row: 1 / span 2; min-height: 36px; padding: .3rem .7rem; font-size: var(--text-sm); }
  .auth-login .legal-footer { padding: .45rem 0 .55rem; font-size: var(--text-sm); }
  .auth-login .legal-footer-links { gap: .15rem .8rem; }
  .auth-login .legal-footer-note { margin-top: .3rem; line-height: 1.4; }
}
/* 800px tall and under (1280 x 800, 1366 x 768): a fixed, smaller top margin. */
@media (min-width: 960px) and (max-height: 800px) {
  .auth-login .auth-form { padding-top: 1.75rem; }
  .auth-login .legal-footer-links { font-size: var(--text-sm); }
  .auth-login .legal-footer-note { font-size: var(--text-sm); }
}
@media (max-width: 959.98px) {
  /* Stacked (phones, tablets): the picture first, full width and as large as
     it can be without shrinking its type — the upper part of the artwork, with
     the logo, the headline and the interior — then the message, then the card. */
  .auth-login { display: block; background: var(--fs-cloud-dancer); }
  .auth-login .auth-side { display: block; height: auto; min-height: 0; }
  .auth-login .entry-art img { object-position: 70% center; }
  .auth-login .entry-art::after { background: linear-gradient(180deg, rgba(10, 18, 24, .9) 0%, rgba(10, 18, 24, .78) 60%, rgba(10, 18, 24, .9) 100%); }
  .auth-login .entry-copy { padding: 1.25rem 1.25rem 1.5rem; }
  .auth-login .entry-logo { margin-bottom: 1rem; }
  .auth-login .entry-logo .lockup-lg { --lockup-h: 24px; }
  .auth-login .entry-eyebrow { letter-spacing: .08em; }
  .auth-login .entry-headline { font-size: clamp(2.6rem, 13.5vw, 5rem); }
  .auth-login .entry-rule { margin: .85rem 0; }
  .auth-login .entry-lede { font-size: 1rem; }
  .auth-login .entry-benefits { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .9rem .75rem; padding-top: 1.25rem; width: 100%; }
  /* Icon beside its two lines, so the four fit in two short rows. */
  .auth-login .entry-benefits li { display: grid; grid-template-columns: 26px minmax(0, 1fr); column-gap: .55rem; row-gap: 0; align-content: start; padding: 0; border-left: 0; }
  .auth-login .entry-icon { grid-row: span 2; width: 26px; height: 26px; margin: 0; }
  .auth-login .entry-benefits strong { font-size: .95rem; line-height: 1.3; }
  .auth-login .entry-benefits span { line-height: 1.35; }
  .auth-login .auth-form { padding: 1.5rem 1.25rem 2rem; border-top: 0; }
  .auth-login .auth-form-body { max-width: 30rem; }
  .auth-login .entry-message-top { font-size: clamp(2.3rem, 13vw, 3.6rem); }
  .auth-login .entry-message-grad { font-size: clamp(1.55rem, 8.2vw, 2.4rem); }
}

/* Tablets: the four benefits back in one row. */
@media (min-width: 600px) and (max-width: 959.98px) {
  .auth-login .entry-copy { padding: 2rem 2.5rem 2.25rem; }
  .auth-login .entry-benefits { grid-template-columns: repeat(4, auto); justify-content: start; gap: 0; }
  .auth-login .entry-benefits li { padding: 0 clamp(.9rem, 1.6vw, 1.5rem); border-left: 1px solid rgba(255, 255, 255, .22); }
  .auth-login .entry-benefits li:first-child { padding-left: 0; border-left: 0; }
  .auth-login .entry-benefits li { display: flex; flex-direction: column; gap: .15rem; }
  .auth-login .entry-icon { width: 32px; height: 32px; margin-bottom: .45rem; }
}

/* ---- the create-your-account page ----
   Only portal/register.html carries .auth-register-art. The LEFT is the supplied
   wall-graphics picture (static/img/register-wallgraphic.webp) filling the panel,
   with the FSVEXAN lockup over its top-left corner; the RIGHT is the usual form.
   The picture is wider than the panel, so the crop keeps its right side — the
   lettered steps (Design, Visualize, Specify, Quotate, Deliver) are never cut. */
.auth-register-art .auth-side { padding: 0; gap: 0; position: relative; overflow: hidden; background: #2a2622; }
.auth-register-art .auth-side-main { position: relative; flex: 1 1 auto; max-width: none; margin: 0; padding: 0; }
.auth-register-art .register-art { position: absolute; inset: 0; display: block; }
.auth-register-art .register-art img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 90% 50%; }
/* A soft shade across the top of the picture (CSS only — the artwork file is untouched), so the
   white lockup stays legible wherever the crop puts it over the pale wall. */
.auth-register-art .auth-side-main::before { content: ""; position: absolute; z-index: 1; inset: 0 0 auto 0; height: 9rem;
  background: linear-gradient(to bottom, rgba(20, 18, 16, .5), rgba(20, 18, 16, 0)); pointer-events: none; }
.auth-register-art .register-logo { position: absolute; z-index: 2; top: .25rem; left: .5rem; display: inline-block; line-height: 0; text-decoration: none; }
.auth-register-art .register-logo:hover { text-decoration: none; }
.auth-register-art .register-logo:focus-visible { outline: 2px solid #fff; outline-offset: 2px; border-radius: 4px; }
.auth-register-art .register-logo .lockup-lg { --lockup-h: clamp(26px, 3.8vh, 34px); --lockup-clear: .5rem; }
.auth-register-art .register-logo .lockup-horizontal.lockup-lg .lockup-logo { min-width: 0; }
.auth-register-art .register-logo .lockup-tagline { text-shadow: 0 1px 6px rgba(0, 0, 0, .55); }
.auth-register-art .register-logo .lockup-logo { filter: drop-shadow(0 1px 4px rgba(0, 0, 0, .45)); }
/* The form's heading is now the page's h1, set exactly as the h2 it was. */
.auth-register-art .auth-form-body > h1 { font-family: var(--font); font-size: 1.6rem; line-height: 1.25; letter-spacing: -.011em; }
@media (min-width: 960px) {
  .auth.auth-register-art { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}
/* A narrower panel (under 1200px wide) crops more of the picture: hold its right edge. */
@media (min-width: 960px) and (max-width: 1199.98px) {
  .auth-register-art .register-art img { object-position: 95% 50%; }
}
@media (max-width: 959.98px) {
  /* Stacked: a compact crop of the picture above the form, the lockup over its ceiling. */
  .auth-register-art .auth-side { display: block; height: auto; min-height: 0; }
  .auth-register-art .auth-side-main { position: relative; }
  /* From the top of the picture, so the lockup sits on the dark ceiling and every step down to
     "Deliver" stays in view. */
  .auth-register-art .register-art { position: static; aspect-ratio: 4 / 3; max-height: 46svh; width: 100%; }
  .auth-register-art .register-art img { object-position: 50% 0%; }
  .auth-register-art .register-logo { top: 0; left: .25rem; }
  .auth-register-art .register-logo .lockup-lg { --lockup-h: 24px; }
  .auth-register-art .auth-side-main::before { height: 5rem; }
}

/* ---- the password-reset page ----
   Only accounts/password_reset.html carries .auth-reset-art, so nothing here
   reaches the other auth pages. The LEFT is one supplied wall-graphics picture
   (static/img/reset-password-wallgraphic.webp), filling the panel; the RIGHT is
   the usual live form. */
.auth-reset-art .auth-side { padding: 0; gap: 0; position: relative; overflow: hidden; background: #1c2230; }
.auth-reset-art .auth-side-main { position: relative; flex: 1 1 auto; max-width: none; margin: 0; padding: 0; }
.auth-reset-art .reset-art { position: absolute; inset: 0; display: block; }
.auth-reset-art .reset-art img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 45%; }
/* The official lockup over the picture's top-left corner; the lockup's own clear space is its padding. */
.auth-reset-art .reset-logo { position: absolute; z-index: 2; top: .25rem; left: .5rem; display: inline-block; line-height: 0; text-decoration: none; }
.auth-reset-art .reset-logo:hover { text-decoration: none; }
.auth-reset-art .reset-logo:focus-visible { outline: 2px solid #fff; outline-offset: 2px; border-radius: 4px; }
.auth-reset-art .reset-logo .lockup-lg { --lockup-h: clamp(26px, 3.8vh, 34px); --lockup-clear: .5rem; }
.auth-reset-art .reset-logo .lockup-horizontal.lockup-lg .lockup-logo { min-width: 0; }
/* The lockup's own tagline, over a photograph: a soft shadow keeps it readable. */
.auth-reset-art .reset-logo .lockup-tagline { text-shadow: 0 1px 6px rgba(0, 0, 0, .55); }
.auth-reset-art .auth-form-body > h1 { margin: 0 0 .5rem; font-size: 1.6rem; font-weight: 600; line-height: 1.25; letter-spacing: -.011em; color: var(--graphite); }
@media (min-width: 960px) {
  .auth.auth-reset-art { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}
@media (max-width: 959.98px) {
  /* Stacked: a compact crop of the picture above the form. */
  .auth-reset-art .auth-side { display: block; height: auto; min-height: 0; }
  .auth-reset-art .auth-side-main { position: static; }
  .auth-reset-art .reset-art { position: static; aspect-ratio: 16 / 10; max-height: 46svh; width: 100%; }
  .auth-reset-art .reset-art img { object-position: 50% 38%; }
  .auth-reset-art .auth-side-main { position: relative; }
  .auth-reset-art .reset-logo { top: 0; left: .25rem; }
  .auth-reset-art .reset-logo .lockup-lg { --lockup-h: 24px; }
}

@media (min-width: 960px) {
  .auth {
    grid-template-columns: minmax(0, 1fr) minmax(460px, 0.9fr);
    height: 100vh; height: 100dvh; min-height: 0; overflow: hidden;
  }
  .auth-side {
    height: 100%; min-height: 0; overflow: hidden auto;
    gap: clamp(1rem, 3.5vh, 2rem);
    padding: clamp(1.5rem, 5vh, 3rem) clamp(2rem, 4vw, 3.5rem);
  }
  .auth-side .lockup-lg { --lockup-h: clamp(40px, 6.5vh, 58px); }
  .auth-side-main { max-width: 30rem; margin-block: auto; }
  .auth-side h1 { font-size: clamp(1.9rem, 4.6vh, 2.5rem); max-width: 14ch; }
  /* "Create your FSVEXAN account." on two lines, like sign in's heading — not three. */
  .auth-register .auth-side h1 { max-width: 19ch; text-wrap: balance; }
  .auth-features { margin-top: clamp(1rem, 3vh, 1.75rem); }
  .auth-side-brand, .auth-side-foot { flex: none; }
  .auth-form {
    height: 100%; min-height: 0; overflow-y: auto; overscroll-behavior: contain; scrollbar-gutter: stable;
    border-left: 1px solid var(--line);
    padding: clamp(1.5rem, 5vh, 3rem) clamp(1.5rem, 4vw, 3.5rem);
  }
}
@media (max-width: 959.98px) {
  /* Stacked: ordinary page scrolling; the scrollbar's space is reserved so
     nothing shifts sideways when the form becomes long enough to scroll. */
  html:has(.auth) { scrollbar-gutter: stable; }
  .auth { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  .auth-side { padding: 1.25rem 1.25rem 1.1rem; gap: .6rem; }
  .auth-side .lockup-lg { --lockup-h: 30px; }
  .auth-eyebrow { margin-bottom: .3rem; font-size: .72rem; }
  .auth-side h1 { font-size: 1.35rem; margin: 0; text-wrap: balance; }
  .auth-lede, .auth-features, .auth-side-foot { display: none; }
  .auth-form { padding: 1.5rem 1.25rem 2.5rem; border-top: 1px solid var(--line); }
  .auth-form-body, .auth-register .auth-form-body { margin: 0 auto; }
  .firm-suggestion { padding-top: .65rem; padding-bottom: .65rem; }
  .firm-suggestion .firm-suggestion-use { min-height: 40px; }
}

.portal-top { background: var(--graphite); color: #fff; }
/* The page container (.container, and the portal's top bar and page, which
   share it so the logo, the navigation and the content always line up).
   Fluid: content uses the whole window less the gutter — about 93% of a
   1280-1536px laptop screen — up to --page-max (1600px), then stays centred
   so a very wide monitor never stretches cards and tables edge to edge.
   Readable line lengths are kept by the text blocks themselves (e.g.
   .hero-lede), not by narrowing the whole page. */
.container, .portal-top .inner, .portal-main {
  width: 100%; max-width: calc(var(--page-max) + 2 * var(--page-gutter)); margin-inline: auto;
  padding-inline: var(--page-gutter);
}
.portal-top .inner { display: flex; align-items: center; justify-content: space-between; gap: 1rem; min-height: 60px; flex-wrap: wrap; }
.portal-top nav { display: flex; gap: .25rem; flex-wrap: wrap; }
.portal-top nav a { color: #dfe3e7; padding: .4rem .7rem; border-radius: var(--radius); }
.portal-top nav a.active, .portal-top nav a:hover { background: var(--graphite-2); color: #fff; text-decoration: none; }
.portal-main { padding-top: 2rem; padding-bottom: 3rem; }

.product-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 1rem; }
.product-item { display: block; background: #fff; border: 1px solid var(--line); border-top: 3px solid var(--graphite); border-radius: var(--radius); padding: 1rem 1.1rem; color: var(--ink); }
/* Dashboard "Price a job" shows Wall Graphics first (it has the instant
   calculator) regardless of the products' natural (alphabetical) order. */
.product-item[data-slug="wall-graphics"] { order: -1; }
.product-item:hover { border-top-color: var(--signal); text-decoration: none; }
.product-item h3 { margin-bottom: .25rem; }
.product-item .how { font-size: var(--text-sm); color: var(--steel); margin-top: .5rem; }
.product-item .how-link { display: inline-block; font-size: var(--text-sm); font-weight: 600; color: var(--blue);
  margin-top: .5rem; }
.product-item .how-link:hover { text-decoration: underline; }
.product-item .how-link.secondary { color: var(--graphite); }
/* A second, clearly-separate action on a "Price a job" card — e.g. Book a
   designer / Book a site visit — never mixed into the instant-price line. */
.product-item-extra { margin-top: .75rem; padding-top: .75rem; border-top: 1px solid var(--line-2); }
.product-item-extra p { margin: 0 0 .35rem; }
.product-item-extra .badge { margin-top: .4rem; }

/* ---------- calculator (the signature element) ---------- */
/* The page is one column of stacked sections (wall sizes, then spec, then
   summary, then the quotation form) — each wall card supplies its own
   inputs-beside-preview layout below, so there's no outer split anymore. */
.calc { display: block; }
.dims { display: grid; grid-template-columns: 1fr 1fr; gap: .75rem; }
/* One card per wall in the project — each keeps its own inputs, preview and
   validation, entirely independent of the others. Inputs sit beside a large
   preview of that same wall so the architect sees the result immediately,
   without scrolling away to a separate preview column. */
.wall-entry { border: 1px solid var(--line); border-radius: var(--radius); padding: 1.1rem 1.25rem;
  background: #fff; }
.wall-entry + .wall-entry { margin-top: 1rem; }
.wall-entry-main { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr); gap: 1.5rem; align-items: start; }
.wall-entry-head { display: flex; justify-content: space-between; align-items: center; gap: .75rem;
  margin-bottom: .75rem; }
.wall-entry-head h3 { margin: 0; }
.wall-error { color: var(--red); font-size: var(--text-sm); margin: .6rem 0 0; }
.wall-amount { font-weight: 600; margin-top: .6rem; text-align: right; font-variant-numeric: tabular-nums; }
.wall-list-actions { display: flex; align-items: center; gap: .75rem; margin-top: 1rem; flex-wrap: wrap; }
.unit-toggle { display: inline-flex; border: 1px solid #c9ced5; border-radius: var(--radius); overflow: hidden; }
.unit-toggle label { margin: 0; font-weight: 500; }
.unit-toggle input { position: absolute; opacity: 0; pointer-events: none; }
.unit-toggle span { display: block; padding: .45rem .8rem; cursor: pointer; border-right: 1px solid #c9ced5; }
.unit-toggle label:last-child span { border-right: 0; }
.unit-toggle input:checked + span { background: var(--graphite); color: #fff; }
.unit-toggle input:focus-visible + span { outline: 2px solid var(--blue); outline-offset: -2px; }
.wall-stage { background: #fbfbfc; border: 1px solid var(--line); border-radius: var(--radius); padding: 1rem; }
/* The room photo and the panel-layout SVG are stacked in the same box, sharing
   the photo's own aspect ratio — so the SVG's viewBox coordinates map exactly
   onto the photographed wall, and the panel overlay always sits ON that wall
   rather than floating as a separate box. */
.wall-visual { position: relative; width: 100%; aspect-ratio: 400 / 260; overflow: hidden;
  border-radius: calc(var(--radius) - 2px); background: #e9e7e2; }
.wall-visual > img, .wall-visual > svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* The empty wall's note (templates/portal/configure.html): centred on the wall above the
   floor line, until a panel layout or artwork is drawn (calculator.js hides it). */
.wall-empty-hint { position: absolute; left: 50%; top: 42%; transform: translate(-50%, -50%);
  width: min(24rem, calc(100% - 2rem)); padding: .9rem 1.1rem; text-align: center;
  background: rgba(255, 255, 255, .88); border: 1px solid var(--line); border-radius: var(--radius-md);
  font-size: var(--text-sm); line-height: 1.45; color: var(--steel); }
.wall-empty-hint[hidden] { display: none; }
.wall-empty-hint p { margin: 0; }
.wall-empty-hint .wall-empty-title { font-weight: 600; color: var(--graphite); margin-bottom: .2rem; }
@media (max-width: 480px) { .wall-empty-hint { padding: .55rem .75rem; line-height: 1.35; } }
/* The wall photo is shown whole — never trimmed — so its floor/base always
   stays visible even when a Settings-uploaded photo isn't exactly 400:260
   (the built-in mockup is, and renders identically either way). */
.wall-placeholder-image { object-fit: contain; }
.wall-caption { font-size: var(--text-sm); color: var(--steel); margin-top: .5rem; min-height: 1.3em; }
.price-block { border: 1px solid var(--line); border-radius: var(--radius); background: #fff; margin-top: 1rem; }
.price-row { display: flex; justify-content: space-between; gap: 1rem; padding: .55rem 1rem; border-bottom: 1px solid var(--line-2); }
.price-row:last-child { border-bottom: 0; }
.price-row.total { background: var(--graphite); color: #fff; border-radius: 0 0 var(--radius) var(--radius); }
.price-row.total .v { font-family: var(--font-cond); font-size: 1.6rem; font-weight: 600; }
.price-row .v { font-variant-numeric: tabular-nums; font-weight: 600; }
.calc-error { color: var(--red); padding: .75rem 1rem; border: 1px solid var(--line); border-radius: var(--radius);
  background: #fff; margin-bottom: 1.25rem; }
.calc-note { font-size: var(--text-sm); color: var(--steel); margin-top: .75rem; }
.calc.loading .price-block { opacity: .6; }
/* A professional, non-blocking heads-up next to Site location — never a
   charge, never a calculation, just a note that we'll confirm transport
   separately for anywhere other than our base city. */
.transport-note { background: var(--blue-tint); border: 1px solid var(--blue); border-radius: var(--radius);
  padding: .6rem .85rem; margin-top: .5rem; font-size: var(--text-sm); line-height: 1.4; }
.transport-note strong { display: block; color: var(--graphite); }
.transport-note p { margin: .25rem 0 0; color: var(--steel); }

/* ---------- quotation document preview ---------- */
.doc { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); }
.doc-lines td { white-space: pre-line; }
/* Line items. Numbers never break ("per sq ft", ₹ amounts); the unit in the Area cell
   only shows on the cards below (the column header already says sq ft). */
.doc-lines td.num { white-space: nowrap; }
.doc-lines .dl-unit { display: none; }
.doc-lines-wrap { container-type: inline-size; }
/* Narrow panel (a laptop's side-by-side layout, tablets, phones): each line is a card —
   number and item across the top, then Qty · Area · Rate · GST inline, amount on the right. */
@container (max-width: 620px) {
  table.doc-lines, table.doc-lines tbody { display: block; }
  table.doc-lines thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  table.doc-lines tr { position: relative; display: flex; flex-wrap: wrap; align-items: baseline; column-gap: .9rem; row-gap: .2rem;
    padding: .85rem 0 .85rem 2.1rem; border-bottom: 1px solid var(--line-2); }
  table.doc-lines tr:last-child { border-bottom: 0; }
  table.data.doc-lines td { padding: 0; border: 0; text-align: left; }
  table.doc-lines td.dl-pos { position: absolute; left: 0; color: var(--steel); }   /* in the indent, so every line below lines up */
  table.doc-lines td.dl-item { flex: 1 1 100%; }
  /* Qty · Area · Rate · GST side by side under the item; the amount pushed to the right. */
  table.doc-lines td[data-label] { flex: 0 0 auto; font-size: var(--text-sm); }
  table.doc-lines td[data-label]::before { content: attr(data-label) " "; color: var(--steel); }
  table.doc-lines td[data-label="Area"]:empty { display: none; }
  table.doc-lines td.dl-amount { margin-left: auto; font-weight: 600; }
  table.doc-lines .dl-unit { display: inline; }
  table.doc-lines .dl-basis { display: inline; margin-left: .2rem; }
  table.doc-lines tr:hover td { background: none; }
}
.totals { width: 100%; max-width: 360px; margin-left: auto; }
.totals td { padding: .3rem 0; }
.totals td:last-child { text-align: right; font-variant-numeric: tabular-nums; }
.totals .grand td { font-family: var(--font-cond); font-size: 1.2rem; font-weight: 600; border-top: 2px solid var(--graphite); padding-top: .5rem; }
.rev-list { display: flex; gap: .4rem; flex-wrap: wrap; }
.rev-list a { padding: .3rem .6rem; border: 1px solid var(--line); border-radius: var(--radius); background: #fff; color: var(--graphite); font-size: .88rem; }
.rev-list a.active { border-color: var(--graphite); background: var(--graphite); color: #fff; }
/* "Not visible to clients": the CRM's own quiet grey surface (was a cream #fff8f2), the dashed
   edge marking it as internal. */
.internal { background: var(--canvas); border: 1px dashed var(--steel-2); border-radius: var(--radius); padding: .75rem 1rem; font-size: .88rem; }
.internal h4 { font-size: .9rem; color: var(--signal-dark); margin-bottom: .4rem; }
details.box { border: 1px solid var(--line); border-radius: var(--radius); background: #fff; margin-bottom: 1rem; }
details.box > summary { cursor: pointer; padding: .75rem 1rem; font-weight: 600; list-style: none; }
details.box > summary::-webkit-details-marker { display: none; }
details.box[open] > summary { border-bottom: 1px solid var(--line-2); }
details.box > div { padding: 1rem; }

.pagination { display: flex; gap: .5rem; align-items: center; justify-content: flex-end; padding: .75rem 0; }

/* ---------- internal quotation builder ---------- */
.builder-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(360px, 480px); gap: 1.25rem; align-items: start; }
.builder-preview { position: sticky; top: 1rem; }
.builder-preview iframe { width: 100%; height: 82vh; border: 1px solid var(--line); border-radius: var(--radius); background: #fff; }
.builder-preview .panel-head { display: flex; justify-content: space-between; align-items: baseline; gap: .5rem; }

/* ---------- one-line rate editor (CRM dashboard -> Service pricing) ---------- */
/* Label, a compact ₹ field and Save on ONE line inside the dashboard's narrow
   right-hand column: the parts are sized to fit there, and the label is the
   only thing allowed to shrink. On a phone, where the column is the whole
   screen, it wraps rather than overflowing. */
.rate-line { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
.rate-line label {
  font-size: var(--text-sm); color: var(--steel); flex: 0 1 auto; min-width: 0;
}
.rate-input { display: inline-flex; align-items: center; gap: .3rem; font-size: var(--text-sm); white-space: nowrap; }
.rate-input .input { width: 6.25rem; min-width: 0; padding: .35rem .45rem; text-align: right; }
.rate-line .btn { flex: 0 0 auto; margin-left: auto; }
.rate-line + .rate-line { margin-top: .4rem; }
/* The resulting architect price, with Save beside it. */
.rate-final {
  margin-top: .6rem; padding-top: .6rem; border-top: 1px solid var(--line-2);
  font-size: var(--text-sm); color: var(--steel);
}
.rate-final strong { color: var(--ink); font-size: var(--text-base); }
/* Whether the rate on screen is saved (green) or still to be saved (amber). */
.rate-status { margin: .6rem 0 0; padding: .45rem .6rem; border-radius: 6px; font-size: var(--text-sm); font-weight: 600; }
.rate-status[hidden] { display: none; }
.rate-status.saved { background: var(--green-tint); color: var(--green); }
.rate-status.unsaved { background: var(--amber-tint); color: var(--amber); }

/* ---------- Industry Library (CRM -> Shop by Industry content) ---------- */
/* The architect-facing side of this feature is styled in portal.css; these
   are the staff screens. Both grids size themselves from the space available,
   so they work from a wide desktop down to a phone without width rules. */
.gallery-search { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
.gallery-search .input { flex: 1 1 14rem; min-width: 0; }
.gallery-filters { display: flex; flex-wrap: wrap; gap: .4rem; }
.chip {
  display: inline-block; font-size: var(--text-sm); text-decoration: none; color: var(--steel);
  background: var(--line-2); border: 1px solid var(--line); border-radius: 999px; padding: .15rem .7rem;
}
a.chip:hover { border-color: var(--blue); color: var(--blue); text-decoration: none; }
.chip.selected { background: var(--brand-ink); border-color: var(--brand-ink); color: #fff; }

.admin-design-grid {
  display: grid; gap: var(--space-md); margin-bottom: var(--space-lg);
  grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 1fr));
}
/* Each card carries its own row of actions, so it keeps a usable width on a
   phone rather than shrinking to two cramped columns. */
.admin-design-card {
  display: flex; flex-direction: column; overflow: hidden; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius-md); box-shadow: var(--shadow-sm);
}
.admin-design-card.inactive { opacity: .62; }
.admin-design-thumb { display: block; background: var(--line-2); }
.admin-design-thumb img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block; }
.admin-design-body { display: flex; flex-direction: column; gap: .35rem; padding: var(--space-sm) var(--space-md) var(--space-md); }
.admin-design-body .muted { font-size: var(--text-sm); }
.admin-design-body .actions { flex-wrap: wrap; gap: .3rem; }

/* Bulk upload: one bar for the batch, one line per file. */
.bulk-bar { height: 8px; background: var(--line-2); border-radius: 999px; overflow: hidden; margin: var(--space-md) 0 .4rem; }
.bulk-bar-fill { height: 100%; width: 0; background: var(--blue); transition: width .15s ease; }
.bulk-results { list-style: none; margin: var(--space-sm) 0 0; padding: 0; max-height: 18rem; overflow-y: auto; font-size: var(--text-sm); }
.bulk-results li { padding: .2rem 0; border-bottom: 1px solid var(--line-2); overflow-wrap: anywhere; }
.bulk-results li.ok { color: var(--steel); }
.bulk-results li.failed { color: #A62828; }

.enquiry-image { width: 100%; height: auto; border-radius: var(--radius-sm); display: block; border: 1px solid var(--line); }

/* ---------- responsive ---------- */
/* Stacked columns are minmax(0, 1fr), never plain 1fr: a plain 1fr column
   grows to fit its widest content (a long table, a row that doesn't wrap)
   and pushes the whole page sideways on a phone. With minmax(0, 1fr) the
   column stays the width of the screen; wide tables scroll inside their own
   .table-wrap instead. */
@media (max-width: 1000px) {
  .grid-main { grid-template-columns: minmax(0, 1fr); }
  /* Editor first, live preview stacked directly underneath — the editor
     is what staff act on; the preview is the reference while doing it. */
  .builder-grid { grid-template-columns: 1fr; }
  .builder-preview { position: static; }
  .builder-preview iframe { height: 70vh; }
}
@media (max-width: 860px) {
  /* Wall inputs first, large preview directly underneath — never side by
     side once there isn't room for both to stay useful. minmax(0, …) so the
     column always shrinks to the card: a wall photo preview sized for a wider
     window (before a resize or a tablet rotation) can never hold it open —
     it re-fits itself to the new width instead. */
  .wall-entry-main { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 820px) {
  .shell { grid-template-columns: 1fr; }
  .sidebar { position: fixed; inset: 0 30% 0 0; z-index: 30; transform: translateX(-100%); transition: transform .2s ease; }
  .shell.nav-open .sidebar { transform: none; }
  .topbar { display: flex; align-items: center; justify-content: space-between; background: var(--graphite); color: #fff; padding: .6rem 1rem; position: sticky; top: 0; z-index: 20; }
  /* The bar's own padding gives the lockup its room, so the lockup's clear space is trimmed here
     and the tagline line doesn't make the sticky bar taller than it was. */
  .topbar .lockup { --lockup-clear: .25rem; }
  .topbar button { background: none; border: 1px solid #4a515a; color: #fff; border-radius: var(--radius); padding: .35rem .7rem; font: inherit; }
  .main { padding: 1rem; }
  .grid-2, .grid-3, .form-grid { grid-template-columns: minmax(0, 1fr); }
}
/* The design editor's calculated values and its optional custom rates. */
.calculated {
  padding: .5rem .65rem; border: 1px dashed var(--line); border-radius: var(--radius-sm);
  background: var(--line-2); color: var(--ink); font-weight: 600;
}
.designer-custom-rates {
  margin: 0 0 1rem; padding: var(--space-sm) var(--space-md) .25rem;
  border-left: 3px solid var(--blue); background: var(--line-2); border-radius: var(--radius-sm);
}

/* The card settings on each row of the Designs list. */
.design-facts { margin: .25rem 0 .1rem; font-size: var(--text-sm); }
.design-facts > div { display: flex; justify-content: space-between; gap: .5rem; padding: .1rem 0; }
.design-facts dt { color: var(--steel); }
.design-facts dd { margin: 0; font-weight: 600; text-align: right; overflow-wrap: anywhere; }

/* ---- Industry Library: the design editor ----
   The form on the left, a live picture of the architect's card on the right.
   The preview borrows the portal card's proportions, but the portal's own
   styles are scoped to body.portal, so it carries its own here. */
.design-editor {
  display: grid; gap: var(--space-lg); align-items: start;
  grid-template-columns: minmax(0, 1fr) minmax(0, 21rem);
}
.design-editor-form { min-width: 0; }
/* Content type: two plain choices, each with what it means for architects. */
.design-kind-options { display: grid; gap: .5rem; }
.design-kind-option {
  display: flex; align-items: flex-start; gap: .55rem; padding: .6rem .75rem; cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--radius); font-weight: 500;
}
/* The form styling gives every widget .input; a radio stays radio-sized. */
.design-kind-option input, .design-kind-option input.input {
  flex: none; width: auto; min-height: 0; margin: .2rem 0 0; padding: 0; border: 0; box-shadow: none;
  accent-color: var(--blue);
}
.design-kind-option:has(input:checked) { border-color: var(--blue); background: var(--blue-tint); }
/* A project photo's wall-size panel: folded to its explanation; values kept. */
.panel.panel-collapsed { background: var(--canvas); }
.panel.panel-collapsed .panel-head { margin-bottom: .35rem; }
.design-editor-preview { min-width: 0; position: sticky; top: var(--space-md); }
.design-size-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }

.card-preview {
  overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius-md);
  background: var(--surface); box-shadow: var(--shadow-sm);
}
.card-preview-media { position: relative; display: block; background: var(--line-2); }
.card-preview-media img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block; }
.card-preview-empty {
  display: flex; align-items: center; justify-content: center; aspect-ratio: 4 / 3;
  color: var(--steel); font-size: var(--text-sm);
}
.card-preview-label {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 1.75rem .9rem .7rem;
  font-size: var(--text-label); letter-spacing: .08em; text-transform: uppercase;
  color: #fff; background: linear-gradient(to top, rgba(20, 22, 26, .72), transparent);
  overflow-wrap: anywhere;
}
.card-preview-facts {
  display: flex; flex-direction: column; gap: .35rem;
  padding: var(--space-md); border-top: 1px solid var(--line-2);
}
.preview-size {
  margin: 0 0 .15rem; font-size: var(--text-sm); letter-spacing: .06em;
  text-transform: uppercase; color: var(--steel);
}
.preview-fact {
  display: flex; align-items: baseline; justify-content: space-between; gap: .5rem;
  font-size: var(--text-sm);
}
.preview-fact > span:first-child { color: var(--steel); overflow-wrap: anywhere; }
.preview-value { font-weight: 600; text-align: right; }
.preview-rate { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: .35rem; justify-content: flex-end; }
.preview-rate .rate-was { color: var(--steel); font-weight: 400; font-size: var(--text-sm); }
.preview-rate .promo-flag { font-weight: 700; }
.card-preview-facts .btn { margin-top: .35rem; justify-content: center; }
.preview-btn { cursor: default; }

@media (max-width: 1000px) {
  .design-editor { grid-template-columns: minmax(0, 1fr); }
  /* On a narrow screen the preview reads better first: the admin sees what
     they are changing before the fields that change it. */
  .design-editor-preview { position: static; order: -1; }
  .design-editor-preview .card-preview { max-width: 21rem; }
}
@media (max-width: 560px) {
  .design-size-grid { grid-template-columns: minmax(0, 1fr); }
}

@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important; } }
@media print { .sidebar, .topbar, .actions, .portal-top { display: none !important; } .shell { display: block; } }

/* Quotation builder: the nine-column item table. The description takes the
   room; numbers line up on the right. On a narrow screen the table scrolls
   inside its own box (.table-wrap), never the page. */
.item-lines .col-desc { min-width: 16rem; }
.item-lines td { vertical-align: top; }
.line-total { margin: .75rem 0; font-size: 1.05rem; }

/* Quotation builder: compact rows, and "+ Add another line item" as a button
   right under them. */
table.data.item-lines td { padding-top: .45rem; padding-bottom: .45rem; }
/* Only the description wraps; every other column stays on one line, so a
   row is one or two lines tall and the numbers line up. */
table.data.item-lines th, table.data.item-lines td { padding-left: .4rem; padding-right: .4rem; }
table.data.item-lines td:not(.col-desc), table.data.item-lines th { white-space: nowrap; }
.item-lines .col-desc { min-width: 10rem; }
.item-lines .row-actions { white-space: nowrap; text-align: right; }
/* Keeps the hidden "Actions" label inside the table's own scroll box, so a
   narrow screen scrolls the table and never the page. */
.item-lines th { position: relative; }
.item-lines .row-actions form { display: inline; }
.item-lines .row-actions .btn { padding: .15rem .3rem; min-height: 0; }
.add-item { margin: .75rem 0 0; }
.add-item > summary { list-style: none; display: inline-flex; cursor: pointer; }
.add-item > summary::-webkit-details-marker { display: none; }
.add-item[open] > summary { margin-bottom: .75rem; }
.add-item-body { border: 1px solid var(--line); border-radius: var(--radius); padding: .9rem; }

/* Quotation -> Add / Edit line item (templates/quotations/line_editor.html).
   A focused form of sensible width: two columns on desktop and tablet, one on
   a phone. The quotation's own context sits above it, read-only. */
.crumbs { font-size: var(--text-sm); color: var(--steel); margin-bottom: .5rem; display: flex; flex-wrap: wrap; gap: .35rem; }
.crumbs a { color: var(--steel); }
.line-context { display: flex; flex-wrap: wrap; gap: .5rem 1.75rem; margin: 0 0 1rem; max-width: 960px; }
.line-context div { min-width: 0; }
.line-context dt { font-size: .75rem; text-transform: uppercase; letter-spacing: .06em; color: var(--steel); }
.line-context dd { margin: 0; font-weight: 600; overflow-wrap: anywhere; }
.line-editor { max-width: 960px; }
.line-editor .field-check label { font-size: var(--text-sm); color: var(--steel); font-weight: 400; }
.line-editor .line-total { margin: 1rem 0; font-size: 1.1rem; }
@media (min-width: 600px) and (max-width: 820px) {
  .line-editor .form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.add-line { margin: .75rem 0 0; }
.line-editor .form-section { margin: 1rem 0 .4rem; padding-top: .7rem; }
.line-editor .editor-footer {
  position: sticky; bottom: 0; z-index: 2; display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: .5rem 1rem; margin: 1rem -1.25rem -1.1rem; padding: .75rem 1.25rem;
  background: var(--surface); border-top: 1px solid var(--line); box-shadow: 0 -4px 12px rgba(16, 24, 40, .06);
  border-radius: 0 0 var(--radius-md) var(--radius-md);
}
.line-editor .editor-footer .line-total { margin: 0; }
.line-editor .editor-footer .actions { margin: 0; }
.line-editor > h3.form-section:first-of-type { margin-top: 0; padding-top: 0; border-top: 0; }

/* CRM pipelines (Quotations, Orders & Projects): stage chips with live
   counts, a plain-words next step, and each row's actions — one button for
   the main next action, the rest in a small "More" menu. */
.stage-chips { display: flex; flex-wrap: wrap; gap: .4rem; margin: 0 0 .9rem; }
.chip-count { display: inline-block; min-width: 1.3rem; margin-left: .25rem; padding: 0 .35rem; border-radius: 999px; background: rgba(0, 0, 0, .07); font-size: .75rem; font-weight: 700; text-align: center; }
.chip.selected .chip-count { background: rgba(255, 255, 255, .25); }
.pipeline-table td { vertical-align: top; }
.pipeline-table .next-step { font-size: .88rem; min-width: 7.5rem; }
.pipeline-actions { display: flex; flex-wrap: wrap; align-items: flex-start; gap: .35rem; }
.pipeline-actions form { display: inline; margin: 0; }
.row-menu > summary { list-style: none; cursor: pointer; }
.row-menu > summary::-webkit-details-marker { display: none; }
.row-menu-list { display: flex; flex-direction: column; margin-top: .35rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); min-width: 11rem; }
.row-menu-item { display: block; width: 100%; padding: .45rem .7rem; text-align: left; background: none; border: 0; font: inherit; font-size: .88rem; color: inherit; cursor: pointer; white-space: nowrap; }
.row-menu-item:hover { background: var(--canvas); text-decoration: none; }
.row-menu-item.danger { color: var(--red); border-top: 1px solid var(--line-2); }
/* One-click term choices under a box in the quotation builder (quotations/builder.html). */
.quick-picks { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .4rem; }
.quick-pick { font: inherit; font-size: var(--text-sm); padding: .25rem .65rem; border-radius: 999px;
  border: 1px solid var(--line); background: var(--surface); color: var(--graphite); cursor: pointer; }
.quick-pick:hover { border-color: var(--steel-2); }
.quick-pick.is-chosen { background: var(--graphite); border-color: var(--graphite); color: #fff; }
.page-head .pipeline-actions { justify-content: flex-end; }
.progress-steps { display: flex; flex-wrap: wrap; gap: .4rem; list-style: none; padding: 0; margin: 0 0 1rem; }
.progress-steps li { padding: .35rem .7rem; border-radius: 999px; border: 1px solid var(--line); font-size: var(--text-sm); color: var(--steel); }
.progress-steps li.done { background: var(--green-tint); border-color: transparent; color: #04794F; }
.progress-steps li.done::before { content: "\2713  "; }
.progress-steps li.current { background: var(--blue-tint); border-color: var(--blue); color: var(--blue); font-weight: 700; }
.doc-list { list-style: none; padding: 0; margin: 0 0 .75rem; }
.doc-list li { padding: .35rem 0; display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; }
/* Long action labels ("Move to Fabrication / production") wrap inside the
   button instead of stretching the column. */
.pipeline-table .pipeline-actions .btn { white-space: normal; text-align: left; max-width: 11rem; line-height: 1.2; }
.pipeline-table td:first-child { min-width: 9.5rem; }
.pipeline-table .badge { white-space: normal; }
table.data.pipeline-table th { white-space: normal; }

/* CRM -> Materials: fits a laptop-width page. Long headers ("Selling rate
   (₹/sq ft)") wrap instead of fixing their columns' width; rates stay on one
   line; the pairings cell is a summary with the full list in "All N pairings". */
table.data.materials-table th { white-space: normal; vertical-align: bottom; }
table.data.materials-table th, table.data.materials-table td { padding-left: .55rem; padding-right: .55rem; }
table.data.materials-table td.num { white-space: nowrap; }
.materials-table .pairing-line + .pairing-line { margin-top: .35rem; }
.materials-table .pairing-warranty { display: block; font-size: var(--text-sm); }
.materials-table .pairing-details { margin-top: .3rem; font-size: var(--text-sm); }
.materials-table .pairing-details > summary { cursor: pointer; color: var(--blue); font-weight: 600; }
.materials-table .pairing-details[open] > summary { margin-bottom: .3rem; }
.materials-table .pairing-details > div + div { margin-top: .15rem; }

/* CRM dashboard: "Needs your attention" — live counts, each a link to the
   filtered list (apps.crm.views._needs_attention). */
.attention { margin-bottom: 1.25rem; }
.attention h2 { font-size: 1rem; margin: 0 0 .6rem; }
/* 1 to 7 tiles (data-n = how many). Every row is filled edge to edge, never a
   lone tile beside a gap: one row on desktop; on tablets up to 4 in a row,
   else 3 a row (6 tracks, 2 each) with the last row's tiles widened to fill
   it; on phones 2 a row, an odd last tile taking the whole row. */
.attention-items { display: grid; grid-template-columns: repeat(var(--n, 4), minmax(0, 1fr)); gap: .6rem; }
@media (min-width: 561px) and (max-width: 1024px) {
  .attention-items[data-n="5"], .attention-items[data-n="6"], .attention-items[data-n="7"] { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .attention-items[data-n="5"] .attention-item, .attention-items[data-n="6"] .attention-item,
  .attention-items[data-n="7"] .attention-item { grid-column: span 2; }
  .attention-items[data-n="5"] .attention-item:nth-child(n+4) { grid-column: span 3; }
  .attention-items[data-n="7"] .attention-item:last-child { grid-column: 1 / -1; }
}
@media (max-width: 560px) {
  .attention-items { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .attention-items[data-n="1"] .attention-item, .attention-items[data-n="3"] .attention-item:last-child,
  .attention-items[data-n="5"] .attention-item:last-child, .attention-items[data-n="7"] .attention-item:last-child { grid-column: 1 / -1; }
}
.attention-item {
  display: flex; align-items: baseline; gap: .6rem; padding: .7rem .9rem; color: inherit; text-decoration: none;
  background: var(--surface); border: 1px solid var(--line); border-left: 3px solid var(--amber, #D97706);
  border-radius: var(--radius-md); box-shadow: var(--shadow-sm);
}
.attention-item:hover { border-color: var(--blue); }
.attention-item .value { font-size: 1.35rem; font-weight: 700; line-height: 1; }
.attention-item .label { font-size: var(--text-sm); color: var(--steel); }

/* Sign-in: "Show password" (templates/accounts/login.html). */
.pw-toggle {
  display: inline-block; background: none; border: 0; padding: 0; margin: -.35rem 0 1rem;
  color: var(--blue); font: inherit; font-size: var(--text-sm); cursor: pointer;
}
.pw-toggle:hover { text-decoration: underline; }
.pw-toggle:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.caps-warning { margin: -.35rem 0 .5rem; font-size: var(--text-sm); font-weight: 600; color: var(--amber, #B45309); }

/* Material master form: manufacturer dropdown with "+ Add manufacturer"
   beside it (templates/catalog/_material_form.html). */
.manufacturer-pick { display: flex; gap: .5rem; align-items: center; }
.manufacturer-pick select { flex: 1; min-width: 0; }
.manufacturer-pick .btn { white-space: nowrap; }

/* CRM -> New quotation: the quotation identity choice
   (templates/quotations/create_identity.html, create.html). */
.identity-choices { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1rem; }
.identity-card {
  display: flex; flex-direction: column; gap: .35rem; padding: 1.25rem 1.4rem; text-decoration: none; color: inherit;
  border: 1.5px solid var(--line); border-radius: var(--radius-md); background: var(--surface); box-shadow: var(--shadow-sm);
}
.identity-card:hover, .identity-card:focus-visible { border-color: var(--blue); }
.identity-name { font-size: 1.25rem; font-weight: 700; letter-spacing: .02em; }
.identity-who { color: var(--steel); font-size: .9rem; }
.identity-chosen { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; margin-bottom: .25rem; }
.radio-inline { display: inline-flex; align-items: center; gap: .4rem; font-weight: 600; padding: .4rem .8rem;
  border: 1px solid var(--line); border-radius: var(--radius-md); cursor: pointer; }
.radio-inline:has(input:checked) { border-color: var(--blue); background: var(--blue-tint); }

/* ============================================================
   Legal pages and the legal footer (templates/legal/,
   templates/partials/legal_footer.html)
   ============================================================ */
.legal-footer { padding: 1.25rem 1rem 1.5rem; border-top: 1px solid var(--line); background: var(--surface);
  font-size: var(--text-sm); color: var(--steel, #69707A); }
.legal-footer-links { display: flex; flex-wrap: wrap; gap: .35rem 1.1rem; justify-content: center; }
.legal-footer-links a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.legal-footer-links a:hover { color: var(--blue); }
.legal-footer-note { margin: .6rem auto 0; max-width: 46rem; text-align: center; line-height: 1.5; }
.auth-form .legal-footer { background: transparent; border-top: 1px solid var(--line-2); margin-top: auto; }

body.legal { background: var(--canvas); }
.legal-top { background: var(--graphite); color: #fff; }
.legal-top-inner { max-width: 60rem; margin: 0 auto; padding: .75rem 1rem; display: flex; flex-wrap: wrap;
  align-items: center; justify-content: space-between; gap: .75rem 1.5rem; }
.legal-brand { display: inline-flex; }
.legal-tabs { display: flex; flex-wrap: wrap; gap: .25rem; }
.legal-tabs a { color: #dfe3e7; padding: .4rem .65rem; border-radius: var(--radius); font-size: var(--text-sm); }
.legal-tabs a:hover, .legal-tabs a[aria-current="page"] { color: #fff; background: rgba(255,255,255,.12); }
.legal-main { padding: 1.5rem 1rem 2.5rem; }
.legal-doc { max-width: 46rem; margin: 0 auto; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-md); padding: 1.75rem 2rem; line-height: 1.65; overflow-wrap: break-word; }
.legal-doc h1 { margin: .25rem 0 .25rem; }
.legal-doc h2 { font-size: 1.2rem; margin: 2rem 0 .6rem; padding-top: .5rem; border-top: 1px solid var(--line-2); scroll-margin-top: 1rem; }
.legal-doc h3 { font-size: 1rem; margin: 1.25rem 0 .35rem; }
.legal-doc section { scroll-margin-top: 1rem; }
.legal-doc ul, .legal-doc ol { padding-left: 1.2rem; }
.legal-doc li { margin-bottom: .3rem; }
.legal-eyebrow { font-size: .78rem; letter-spacing: .06em; text-transform: uppercase; color: var(--steel, #69707A); margin: 0; }
.legal-updated { color: var(--steel, #69707A); font-size: var(--text-sm); margin-top: 0; }
.legal-lede { font-size: 1.05rem; }
.legal-toc { border: 1px solid var(--line-2); border-radius: var(--radius-md); padding: .9rem 1.1rem; margin: 1.25rem 0; background: var(--canvas); }
.legal-toc-title { font-weight: 600; margin: 0 0 .4rem; }
.legal-toc ol { margin: 0; columns: 2 16rem; column-gap: 1.5rem; }
.legal-facts { display: grid; gap: .35rem; margin: .75rem 0; }
.legal-facts div { display: grid; grid-template-columns: minmax(7rem, 11rem) 1fr; gap: .75rem; }
.legal-facts dt { font-weight: 600; }
.legal-facts dd { margin: 0; }
.legal-doc .pre { white-space: pre-line; }
.legal-table-wrap { overflow-x: auto; margin: .75rem 0; }
.legal-table { width: 100%; border-collapse: collapse; font-size: .95rem; }
.legal-table th, .legal-table td { text-align: left; vertical-align: top; padding: .6rem .7rem; border: 1px solid var(--line-2); }
.legal-table thead th { background: var(--canvas); }
.legal-table tbody th { font-weight: 600; width: 38%; }
.legal-internal { margin: 1rem 0; padding: .65rem .85rem; border-left: 4px solid #B45309; background: #FEF3C7;
  color: #78350F; font-size: var(--text-sm); border-radius: var(--radius); }
.legal-internal a { color: inherit; text-decoration: underline; }
.legal-review-list li { margin-bottom: .55rem; }
@media (max-width: 640px) {
  .legal-doc { padding: 1.25rem 1rem; border-radius: 0; border-left: 0; border-right: 0; }
  .legal-main { padding: 0 0 2rem; }
  .legal-facts div { grid-template-columns: 1fr; gap: 0; }
  /* Each row becomes a block: the row title above its text, full width. */
  .legal-table thead { display: none; }
  .legal-table, .legal-table tbody, .legal-table tr, .legal-table th, .legal-table td { display: block; width: auto; }
  .legal-table tr { border: 1px solid var(--line-2); border-radius: var(--radius); margin-bottom: .6rem; }
  .legal-table th, .legal-table td { border: 0; }
  .legal-table tbody th { background: var(--canvas); width: auto; }
}

/* ============================================================
   PAGE NOT FOUND (templates/404.html) — the brand, a blank wall in Deep Ivy
   with 404 set on it, one line about what happened, home or contact us.
   ============================================================ */
body.notfound-page { background: var(--fs-cloud-dancer); }
.notfound { min-height: 100vh; min-height: 100dvh; display: flex; flex-direction: column;
  padding: clamp(1rem, 3vw, 2rem) clamp(1rem, 4vw, 3rem) clamp(2rem, 6vh, 4rem); }
.notfound-brand { align-self: flex-start; line-height: 0; }
.notfound-brand .lockup { padding: 0; }
.notfound-body { flex: 1 1 auto; display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; width: 100%; max-width: 34rem; margin: 0 auto; padding-top: clamp(1.5rem, 5vh, 3rem); }
.notfound-wall { position: relative; width: min(100%, 26rem); aspect-ratio: 16 / 9; margin: 0 0 clamp(1.5rem, 4vh, 2.25rem);
  border-radius: 16px; overflow: hidden; container-type: inline-size;
  box-shadow: 0 22px 44px -26px rgba(32, 50, 43, .55); background: #2E4A3F; }
.notfound-wall img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.notfound-wall figcaption { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 2cqw; color: #EFEBE2; }
.notfound-wall-eyebrow { font-size: max(9px, 3cqw); font-weight: 600; letter-spacing: .34em; text-transform: uppercase; opacity: .9; }
.notfound-wall-code { font-family: var(--font-display); font-weight: 700; font-size: 24cqw; line-height: .9; letter-spacing: -.02em; }
.notfound h1 { margin: 0 0 .6rem; font-size: clamp(1.6rem, 1.3rem + 1.2vw, 2.2rem); color: var(--fs-deep-ivy); text-wrap: balance; }
.notfound-lede { margin: 0 0 1.5rem; color: var(--fs-ivy-muted, #4d5f57); font-size: 1.02rem; line-height: 1.55; max-width: 28rem; }
.notfound-actions { display: flex; flex-wrap: wrap; gap: .6rem; justify-content: center; }
.notfound-actions .btn { min-height: 44px; padding: .6rem 1.25rem; }
.notfound-actions .btn.primary { background: var(--fs-deep-ivy); border-color: var(--fs-deep-ivy); color: var(--fs-cloud-dancer); }
.notfound-actions .btn.primary:hover { background: var(--fs-ivy-strong, #263c33); border-color: var(--fs-ivy-strong, #263c33); }
.notfound-actions .btn.ghost { background: transparent; border-color: var(--fs-ivy-line, #b9c3bd); color: var(--fs-deep-ivy); }
.notfound-actions .btn.ghost:hover { background: var(--fs-pale-sage, #E4EBE1); }
@media (max-width: 480px) {
  .notfound-actions .btn { flex: 1 1 100%; justify-content: center; }
  .notfound-brand .lockup-md { --lockup-h: 22px; }
}

/* ---- product page: the rates table (templates/catalog/_rate_table.html) ----
   Two rates per row, what pricing uses, and whether the row is saved. */
.rate-table th .th-sub { display: block; font-weight: 400; color: var(--steel); text-transform: none; letter-spacing: 0; }
.rate-table td.num .input { width: 8.5rem; max-width: 100%; text-align: right; }
.rate-table .rate-used { display: block; font-weight: 700; color: var(--graphite); }
.rate-table .rate-used small { font-weight: 500; color: var(--steel); }
.rate-table .rate-source { display: block; font-size: var(--text-sm); color: #4a4a4f; }
.rate-table .rate-save-cell { white-space: nowrap; }
.rate-table .rate-save-cell form { display: inline-block; vertical-align: middle; }
.rate-table .rate-status { display: inline-block; min-width: 7.5rem; margin-left: .5rem; text-align: left; vertical-align: middle; }
.rate-saved { display: inline-flex; align-items: center; gap: .3rem; padding: .15rem .55rem; border-radius: 999px;
  background: #e3f4e8; color: #17663a; font-size: var(--text-sm); font-weight: 700; }
.rate-unsaved { display: inline-flex; padding: .15rem .55rem; border-radius: 999px; background: #fff4dc; color: #7a4b00;
  font-size: var(--text-sm); font-weight: 700; }
.rate-table tr.is-saved td { background: #f2faf4; }
.rate-table tr.is-dirty td { background: #fffaf0; }
.rate-table tr.is-error td { background: #fdf1f0; }
.rate-table tr.rate-row { scroll-margin-top: 5rem; }
.rate-pricelist { margin: .25rem 0 1rem; padding: .6rem .8rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
