/* Portal shell. The back-office at /admin/ has its own stylesheet (Unfold) and
   shares nothing with this file.

   The portal wears Arrowstone's own kit, lifted from arrowstonecabinetry.com:
   Marcellus over Montserrat, black and greys on white, hairline rules and
   black pill buttons; boxed fields and small-cornered cards where people work.
   Every shared value -- colour, type, corners, shadows, sizes -- is a token in
   :root below, and every rule reads the token. */

:root {
  /* ======================================================== shared values
     Every rule below reads these; a rule never types a colour, a corner, a
     shadow, a text size or a control height of its own. Five groups. */

  /* --- Colour: surfaces */
  --portal-surface: #ffffff;
  --portal-panel: #f5f5f5;          /* the only filled panels */
  --portal-head: #f3f3f3;           /* a card's head, a table's top group row */
  --portal-raised: #fafafa;         /* a nested group row, a drop zone */
  --portal-chosen: #f6f6f6;         /* the chosen tile */
  --portal-disabled: #f4f4f4;       /* a field that cannot change */
  --portal-badge: #ebebeb;          /* a grey count or state badge */
  --portal-hover: rgba(0, 0, 0, 0.06);
  --portal-hover-faint: rgba(0, 0, 0, 0.03);
  --portal-scrim: rgba(0, 0, 0, 0.12);   /* behind a pop-up */
  --portal-scrim-strong: rgba(0, 0, 0, 0.42);   /* behind a full-screen modal */
  --portal-veil: rgba(255, 255, 255, 0.92);     /* a caption over a picture */

  /* --- Colour: text. The greys are darker than the marketing site's: a page
     someone works on is read at length and often on a shop laptop in daylight,
     so every one of these clears 4.5:1 on white rather than looking delicate. */
  --portal-ink: #000000;
  --portal-body: rgba(0, 0, 0, 0.84);
  --portal-muted: rgba(0, 0, 0, 0.68);
  --portal-faint: rgba(0, 0, 0, 0.58);
  --portal-ghost: rgba(0, 0, 0, 0.56);
  --portal-ink-hover: rgba(0, 0, 0, 0.78);   /* a black button under the pointer */

  /* --- Colour: lines */
  --portal-rule: rgba(0, 0, 0, 0.09);
  --portal-rule-strong: rgba(0, 0, 0, 0.16);
  --portal-edge: #b5b5b5;           /* a field's box, an outlined button */
  --portal-edge-soft: #c9c9c9;      /* a choice tile */
  --portal-edge-disabled: #d6d6d6;
  --portal-edge-hover: rgba(0, 0, 0, 0.5);

  /* --- Colour: a cabinet drawn in grey (the Door design swatch) */
  --portal-draw-line: rgba(0, 0, 0, 0.35);
  --portal-draw-open: rgba(0, 0, 0, 0.12);
  --portal-draw-toe-kick: rgba(0, 0, 0, 0.28);

  /* --- Colour: meaning. Each a text colour and the wash it sits on. */
  --portal-danger: #9c2b21;
  --portal-danger-strong: #7f2219;
  --portal-danger-wash: #fbf1f0;
  --portal-danger-tint: #fbe3e0;
  --portal-positive: #2f6b3d;
  --portal-positive-wash: #e5f1e8;
  --portal-amber: #7a4900;
  --portal-amber-wash: #fbefd9;
  --portal-amber-faint: #fdf8ee;
  --portal-teal: #1c5f5f;           /* focus, a note, Contacted */
  --portal-teal-wash: #e2f0ef;
  --portal-teal-ring: #d3e8e6;
  --portal-note: #edf4f3;
  --portal-note-ink: #163f3f;
  --portal-blue: #1f4e8c;           /* New, a call */
  --portal-blue-wash: #e6eef8;
  --portal-purple: #553a85;         /* Designing, an email */
  --portal-purple-wash: #eee9f6;
  --portal-brown: #7a4b12;          /* a meeting */
  --portal-brown-wash: #f6ede1;
  --portal-stone: #51504c;          /* Lost, a Stage with no colour of its own */
  --portal-stone-wash: #f2f2ef;

  /* --- Type: Marcellus over Montserrat, and one scale of sizes, named in px. */
  --portal-display: Marcellus, Georgia, "Times New Roman", serif;
  --portal-ui: Montserrat, "Segoe UI", system-ui, -apple-system, sans-serif;
  --portal-text-10: 0.656rem;       /* spaced capitals */
  --portal-text-11: 0.688rem;
  --portal-text-12: 0.75rem;
  --portal-text-13: 0.813rem;
  --portal-text-14: 0.875rem;
  --portal-text-15: 0.938rem;
  --portal-text-16: 1rem;
  --portal-text-18: 1.125rem;
  --portal-text-20: 1.25rem;
  --portal-text-22: 1.375rem;
  --portal-text-24: 1.5rem;
  --portal-text-30: 1.875rem;
  --portal-text-40: 2.5rem;
  --portal-text-44: 2.75rem;
  --portal-text-50: 3.125rem;
  --portal-text-62: 3.875rem;

  /* --- Corners: one for every box (a field, a tile, a note, a card, a table, a
     menu, a badge), twice that for a pop-up, a pill for a button or a tag. */
  --portal-radius: 4px;
  --portal-radius-pop: calc(2 * var(--portal-radius));
  --portal-pill: 999px;
  --portal-round: 50%;

  /* --- Shadows */
  --portal-shadow-pop: 0 16px 48px rgba(0, 0, 0, 0.2);
  --portal-shadow-menu: 0 8px 24px rgba(0, 0, 0, 0.12);
  --portal-shadow-lift: 0 6px 18px rgba(0, 0, 0, 0.16);
  --portal-focus-ring: 0 0 0 3px var(--portal-teal-ring);

  /* --- Sizes */
  --portal-control: 2.75rem;        /* a field, a form's button */
  --portal-control-sm: 2.5rem;      /* a toolbar's button, a search box */
  --portal-control-xs: 1.75rem;     /* a card's own small button */
  --portal-measure: 76rem;
  --portal-gutter: 3.5rem;
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  font: 400 var(--portal-text-15)/1.7 var(--portal-ui);
  color: var(--portal-body);
  background: var(--portal-surface);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
  margin: 0 0 0.5rem;
  font-family: var(--portal-display);
  font-weight: 400;
  line-height: 1.06;
  color: var(--portal-ink);
}

h1 { font-size: var(--portal-text-50); }
h2 { font-size: var(--portal-text-22); }

a { color: var(--portal-ink); text-decoration: none; }
a:hover { color: var(--portal-muted); }

:focus-visible { outline: 2px solid var(--portal-ink); outline-offset: 3px; }

/* A label the eye skips until it needs it: small, tracked, upper case. */
.portal-eyebrow {
  margin: 0 0 0.75rem;
  font-size: var(--portal-text-10);
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--portal-faint);
}

.portal-lede {
  margin: 0 0 1.5rem;
  max-width: 34rem;
  color: var(--portal-muted);
}

/* ---------------------------------------------------------------- header */

.portal-header {
  display: flex;
  align-items: center;
  gap: 3rem;
  padding: 1.375rem var(--portal-gutter);
  border-bottom: 1px solid var(--portal-rule);
}

.portal-brand { position: relative; display: inline-flex; flex: none; align-items: center; }
/* Off Home, a small arrow in the gutter says the logo goes back there. It hangs
   outside the link's box, so the logo never moves. */
.portal-brand-home {
  position: absolute;
  right: calc(100% + 0.5rem);
  font-size: var(--portal-text-14);
  line-height: 1;
  color: var(--portal-faint);
}
.portal-brand:hover .portal-brand-home { color: var(--portal-ink); }
.portal-brand img { height: 36px; width: auto; display: block; }

/* The function on screen (partials/function_nav.html): its name, a size under the
   logo, then its tabs. Functions are picked from Home, so there is no row of them. */
.portal-function {
  display: flex;
  align-items: center;
  gap: 0.5rem 2rem;
  min-width: 0;
  /* Close to the logo: the header's own gap would push it too far off. */
  margin-left: -1.5rem;
  padding-left: 1.5rem;
  border-left: 1px solid var(--portal-rule-strong);
}
.portal-function-name {
  font: 400 var(--portal-text-20)/1.1 var(--portal-display);
  color: var(--portal-ink);
  white-space: nowrap;
}
.portal-function-name:hover { color: var(--portal-ink); }
/* The tabs give way before the Partner menu does: short of room, they scroll
   sideways rather than run under it (and under 60rem they get a line of their own). */
.portal-function-tabs {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: thin;
}
.portal-function-tabs a {
  padding: 0.25rem 0;
  font-size: var(--portal-text-13);
  font-weight: 500;
  color: var(--portal-muted);
  white-space: nowrap;
  border-bottom: 2px solid transparent;
}
.portal-function-tabs a:hover { color: var(--portal-ink); }
.portal-function-tabs a[aria-current="page"] {
  font-weight: 600;
  color: var(--portal-ink);
  border-bottom-color: var(--portal-ink);
}
.portal-header .portal-partner-menu { margin-left: auto; }

/* The Partner a Partner user is signed in under: the one thing on a shared computer
   that must never be a guess, so it is read off the chrome without opening
   anything -- and it is the button everything about signing in hangs from. */
.portal-partner-menu > summary {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.125rem;
  font-size: var(--portal-text-13);
  line-height: 1.35;
  white-space: nowrap;
}
/* No disclosure triangle on this one: the name is the button, and the caret
   sits beside it rather than in front of a two-line block. */
.portal-partner-menu > summary { list-style: none; }
.portal-partner-menu > summary::-webkit-details-marker { display: none; }
.portal-partner-name::after { content: " ▾"; color: var(--portal-faint); }
.portal-partner-name { font-weight: 600; color: var(--portal-ink); }
.portal-user { font-size: var(--portal-text-12); color: var(--portal-muted); }

/* Whose signing-in this is, above the things it lets them do. */
.portal-menu-head {
  margin: 0 0 0.875rem;
  padding-bottom: 0.875rem;
  font-size: var(--portal-text-12);
  color: var(--portal-faint);
  border-bottom: 1px solid var(--portal-rule);
}
.portal-menu-links {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.875rem;
}
.portal-menu-links a,
.portal-signout button {
  font-family: inherit;
  font-size: var(--portal-text-10);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--portal-faint);
}
.portal-menu-links a:hover,
.portal-signout button:hover { color: var(--portal-ink); }

.portal-signout { margin: 0; }
.portal-signout button { padding: 0; border: 0; background: none; cursor: pointer; }

/* ----------------------------------------------------------------- main */

.portal-main {
  flex: 1;
  width: 100%;
  max-width: var(--portal-measure);
  margin: 0 auto;
  padding: 3.5rem var(--portal-gutter) 4rem;
}

.portal-page-head-actions {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  flex: none;
}

/* -------------------------------------------------------------- messages */

.portal-messages {
  width: 100%;
  max-width: var(--portal-measure);
  margin: 1.5rem auto -1.5rem;
  padding: 0 var(--portal-gutter);
  list-style: none;
}
.portal-messages li {
  padding: 0.875rem 1.125rem;
  margin-bottom: 0.5rem;
  background: var(--portal-panel);
  font-size: var(--portal-text-14);
}
.portal-messages li.error { background: var(--portal-danger-wash); color: var(--portal-danger); }

/* ----------------------------------------------------------------- forms

   One look for every form (partials/form_field.html): a plain name on each field, its
   hint before the box, boxes you can see, choices as tiles to click, and only the
   optional fields marked, since most are needed. Hairlines and pills stay the kit's;
   a field is the one place a box is drawn, because an empty underline reads as nothing. */

.portal-form { max-width: 30rem; }

.portal-field {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  min-width: 0;
  margin: 0 0 1.25rem;
  padding: 0;
  border: 0;
}

.portal-field-label {
  display: block;
  margin: 0;
  padding: 0;
  font-size: var(--portal-text-14);
  font-weight: 600;
  line-height: 1.4;
  color: var(--portal-ink);
}
.portal-field-optional {
  margin-left: 0.375rem;
  font-size: var(--portal-text-13);
  font-weight: 400;
  color: var(--portal-muted);
}

.portal-field .helptext {
  display: block;
  margin: 0;
  font-size: var(--portal-text-13);
  line-height: 1.45;
  color: var(--portal-muted);
}
.portal-field .helptext ul { margin: 0; padding-left: 1.1rem; }

.portal-field input:not([type="radio"], [type="checkbox"], [type="file"]),
.portal-field select,
.portal-field textarea,
.portal-input {
  display: block;
  width: 100%;
  height: var(--portal-control);
  margin: 0;
  padding: 0 0.75rem;
  font: 400 var(--portal-text-15)/1.5 var(--portal-ui);
  color: var(--portal-ink);
  background-color: var(--portal-surface);
  border: 1px solid var(--portal-edge);
  border-radius: var(--portal-radius);
}
/* The same box for an input that stands outside a field, sized for a card's toolbar
   (a files card's Kind). */
.portal-input { width: auto; height: var(--portal-control-sm); font-size: var(--portal-text-14); }
/* Grows downwards only, so dragging it never breaks the column it sits in. */
.portal-field textarea {
  height: auto;
  min-height: 5.5rem;
  padding: 0.625rem 0.75rem;
  resize: vertical;
}
.portal-field select,
select.portal-input {
  appearance: none;
  padding-right: 2.25rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14'%3E%3Cpath d='M3 5.5l4 4 4-4' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  background-size: 14px;
}
.portal-field input::placeholder,
.portal-field textarea::placeholder { color: var(--portal-ghost); }
.portal-field input:not([type="radio"], [type="checkbox"], [type="file"]):hover,
.portal-field select:hover,
.portal-field textarea:hover,
.portal-input:hover { border-color: var(--portal-edge-hover); }
.portal-field input:not([type="radio"], [type="checkbox"], [type="file"]):focus,
.portal-field select:focus,
.portal-field textarea:focus,
.portal-input:focus {
  outline: none;
  border-color: var(--portal-teal);
  box-shadow: var(--portal-focus-ring);
}
.portal-field input:disabled,
.portal-field select:disabled,
.portal-field textarea:disabled {
  color: var(--portal-muted);
  background-color: var(--portal-disabled);
  border-color: var(--portal-edge-disabled);
  cursor: default;
}

.portal-field--invalid input:not([type="radio"], [type="checkbox"], [type="file"]),
.portal-field--invalid select,
.portal-field--invalid textarea { border-color: var(--portal-danger); }

/* A choice of a few (a Lost reason, who reached whom, delivery or pickup): tiles two to
   a row, the chosen one outlined in black. A single tick box is one tile of its own. */
.portal-field--choice > div {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.5rem;
}
.portal-field--choice > div > div { display: flex; }
.portal-field--choice label,
.portal-tile {
  display: flex;
  flex: 1;
  align-items: flex-start;
  gap: 0.625rem;
  min-height: 3rem;
  margin: 0;
  padding: 0.75rem 0.875rem;
  font-size: var(--portal-text-15);
  font-weight: 400;
  line-height: 1.4;
  color: var(--portal-ink);
  background: var(--portal-surface);
  border: 1px solid var(--portal-edge-soft);
  border-radius: var(--portal-radius);
  cursor: pointer;
}
.portal-field--choice label:hover,
.portal-tile:hover { border-color: var(--portal-edge-hover); }
.portal-field--choice label:has(input:checked),
.portal-tile:has(input:checked) {
  background: var(--portal-chosen);
  border-color: var(--portal-ink);
  box-shadow: inset 0 0 0 1px var(--portal-ink);
}
.portal-field--choice label:has(input:focus-visible),
.portal-tile:has(input:focus-visible) { outline: 2px solid var(--portal-teal); outline-offset: 2px; }
.portal-field--choice input,
.portal-tile input {
  flex: none;
  width: 1rem;
  height: 1rem;
  margin: 0.125rem 0 0;
  accent-color: var(--portal-ink);
}
.portal-tile small.helptext { margin-top: 0.125rem; }
.portal-field--invalid .portal-tile,
.portal-field--invalid.portal-field--choice label { border-color: var(--portal-danger); }
@media (max-width: 30rem) {
  .portal-field--choice > div { grid-template-columns: minmax(0, 1fr); }
}

/* A file to send (a Settings logo): its button a small outlined pill. */
.portal-field input[type="file"] {
  font-size: var(--portal-text-13);
  color: var(--portal-muted);
  cursor: pointer;
}
.portal-field input[type="file"]::file-selector-button {
  margin-right: 1rem;
  height: var(--portal-control-sm);
  padding: 0 1.125rem;
  font: 600 var(--portal-text-13) var(--portal-ui);
  color: var(--portal-ink);
  background: var(--portal-surface);
  border: 0;
  box-shadow: inset 0 0 0 1px var(--portal-edge);
  border-radius: var(--portal-pill);
  cursor: pointer;
}
.portal-field input[type="file"]:hover::file-selector-button { box-shadow: inset 0 0 0 1px var(--portal-ink); }
.portal-field input[type="file"]:disabled,
.portal-field input[type="file"]:disabled::file-selector-button { cursor: default; opacity: 0.6; }
/* The kept logo, shown above its file input, and the tick that removes it. */
.portal-logo-preview {
  display: block;
  max-width: 12rem;
  max-height: 4rem;
  margin: 0 0 0.5rem;
}
.portal-field label.portal-logo-remove {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.5rem;
  font-size: var(--portal-text-14);
  color: var(--portal-body);
  cursor: pointer;
}
.portal-field .portal-logo-remove input[type="checkbox"] {
  width: auto;
  height: auto;
  margin: 0;
  accent-color: var(--portal-ink);
}

/* What was wrong, under the box, behind a small warning mark. */
ul.errorlist {
  margin: 0 0 0.75rem;
  padding: 0;
  list-style: none;
  font-size: var(--portal-text-13);
  line-height: 1.45;
  color: var(--portal-danger);
}
.portal-field ul.errorlist { margin: 0; }
.portal-field ul.errorlist li { display: flex; align-items: flex-start; gap: 0.375rem; }
.portal-field ul.errorlist li::before {
  content: "";
  flex: none;
  width: 14px;
  height: 14px;
  margin-top: 0.125rem;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Ccircle cx='7' cy='7' r='6.25' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M7 3.8v4M7 9.6v.6' stroke='%23000' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Ccircle cx='7' cy='7' r='6.25' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M7 3.8v4M7 9.6v.6' stroke='%23000' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
}
ul.errorlist.nonfield {
  margin-bottom: 1.25rem;
  padding: 0.75rem 0.875rem;
  background: var(--portal-danger-wash);
  border-radius: var(--portal-radius);
}

/* A group of fields under its own name (a Settings section). */
.portal-form-group-title { margin: 0 0 0.25rem; font: 400 var(--portal-text-20)/1.3 var(--portal-display); color: var(--portal-ink); }

/* A line the form says before its fields, in the teal of the portal's notes. */
.portal-note {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  margin: 0 0 1.25rem;
  padding: 0.75rem 0.875rem;
  font-size: var(--portal-text-14);
  line-height: 1.5;
  color: var(--portal-note-ink);
  background: var(--portal-note);
  border-radius: var(--portal-radius);
}

.portal-button,
.portal-form button[type="submit"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 3.25rem;
  padding: 0 2.125rem;
  font-family: inherit;
  font-size: var(--portal-text-12);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--portal-surface);
  background: var(--portal-ink);
  border: 0;
  border-radius: var(--portal-pill);
  cursor: pointer;
  white-space: nowrap;
}
.portal-button:hover,
.portal-form button[type="submit"]:hover { background: var(--portal-ink-hover); color: var(--portal-surface); }
/* A form's own buttons: the one action black, a second one outlined, one that cannot
   be undone red, and Cancel plain text. */
.portal-form button[type="submit"],
.portal-form .portal-button {
  height: var(--portal-control);
  padding: 0 1.5rem;
  font-size: var(--portal-text-14);
  letter-spacing: 0;
  text-transform: none;
  border-radius: var(--portal-pill);
}
.portal-form button.portal-button--line,
.portal-button--line { color: var(--portal-ink); background: var(--portal-surface); box-shadow: inset 0 0 0 1px var(--portal-edge); }
.portal-form button.portal-button--line:hover,
.portal-button--line:hover { color: var(--portal-ink); background: var(--portal-surface); box-shadow: inset 0 0 0 1px var(--portal-ink); }
.portal-form button.portal-button--danger,
.portal-button--danger { background: var(--portal-danger); }
.portal-form button.portal-button--danger:hover,
.portal-button--danger:hover { background: var(--portal-danger-strong); }

.portal-form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1.75rem;
}
.portal-quiet { font-size: var(--portal-text-13); color: var(--portal-muted); }
.portal-form-actions .portal-quiet {
  display: inline-flex;
  align-items: center;
  height: var(--portal-control);
  padding: 0 0.875rem;
  font: 500 var(--portal-text-14) var(--portal-ui);
  color: var(--portal-body);
  text-decoration: none;
  background: none;
  border: 0;
  cursor: pointer;
}
.portal-form-actions .portal-quiet:hover { color: var(--portal-ink); text-decoration: underline; }

/* ------------------------------------------------------------ sign-in page

   The one screen a Partner user meets before the shell means anything: it drops the
   shell, keeps the sheet on the left, and gives the right half to a kitchen. */

.portal-auth {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(0, 860fr) minmax(0, 580fr);
  max-width: none;
  padding: 0;
}

.portal-auth-sheet {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 2.5rem;
  padding: 2.75rem 4.5rem 2.5rem;
}

.portal-auth-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
}
.portal-auth-top img { height: 34px; width: auto; display: block; }
.portal-auth-kicker {
  font-size: var(--portal-text-10);
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--portal-faint);
}

.portal-auth-body { max-width: 35rem; }
.portal-auth-body h1 { font-size: var(--portal-text-62); }
.portal-auth-body .portal-lede { max-width: 27rem; margin-bottom: 2.5rem; }

.portal-auth-fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2.5rem;
  max-width: 32.5rem;
}
.portal-auth-fields .portal-field { margin: 0; }

.portal-auth .portal-form { max-width: none; }
.portal-auth-actions {
  display: flex;
  align-items: center;
  gap: 1.75rem;
  margin-top: 2.5rem;
}

.portal-auth-register {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.625rem;
  margin: 2.5rem 0 0;
  padding-top: 1.625rem;
  border-top: 1px solid var(--portal-rule);
  font-size: var(--portal-text-13);
  color: var(--portal-muted);
}
.portal-auth-register a {
  font-weight: 500;
  border-bottom: 1px solid var(--portal-rule-strong);
  padding-bottom: 1px;
}

.portal-auth-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  font-size: var(--portal-text-11);
  color: var(--portal-faint);
}

.portal-auth-view { position: relative; background: var(--portal-panel); overflow: hidden; }
.portal-auth-view img { width: 100%; height: 100%; object-fit: cover; display: block; }
.portal-auth-caption {
  position: absolute;
  left: 2rem;
  bottom: 2rem;
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.625rem 1rem;
  background: var(--portal-veil);
  font-size: var(--portal-text-11);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--portal-body);
}
.portal-swatch { width: 12px; height: 12px; border-radius: var(--portal-round); display: inline-block; }

/* ------------------------------------------------------------- page parts */

.portal-page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 3rem;
  margin-bottom: 2.5rem;
}
.portal-page-head p { margin: 0.75rem 0 0; color: var(--portal-muted); font-size: var(--portal-text-14); }

/* Who started a thing and when it was last touched: true, useful once, and
   never the reason anyone opened the screen. It is set small and grey and it
   stays there. */
.portal-meta { margin: 0.75rem 0 0; font-size: var(--portal-text-13); color: var(--portal-faint); }

/* One number the screen is answerable for, under its section head. */
.portal-total { margin: 0.75rem 0 2.5rem; font-size: var(--portal-text-15); color: var(--portal-body); }

.portal-split {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 5rem;
  align-items: start;
}

.portal-panel { background: var(--portal-panel); padding: 1.5rem 1.625rem; }
.portal-panel .portal-eyebrow { margin-bottom: 0.875rem; }

.portal-checklist { margin: 0; padding: 0; list-style: none; }
.portal-checklist li {
  padding: 0.625rem 0;
  border-top: 1px solid var(--portal-rule);
  font-size: var(--portal-text-14);
  line-height: 1.5;
  color: var(--portal-body);
}

/* Rows, not tiles: a rule under each, nothing boxed. */
.portal-rows { border-top: 1px solid var(--portal-rule-strong); }
.portal-row {
  display: flex;
  align-items: center;
  gap: 1.375rem;
  padding: 1rem 0;
  border-bottom: 1px solid var(--portal-rule);
}
.portal-row-index { font-size: var(--portal-text-11); letter-spacing: 0.12em; color: var(--portal-ghost); }
.portal-row-name {
  width: 12rem;
  font-family: var(--portal-display);
  font-size: var(--portal-text-22);
  color: var(--portal-ink);
}
.portal-row-note { flex: 1; font-size: var(--portal-text-14); color: var(--portal-muted); }
.portal-row-state {
  font-size: var(--portal-text-10);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--portal-ghost);
}

.portal-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 2rem;
}
.portal-section-head .portal-eyebrow { margin-bottom: 0; }
.portal-section-note { font-size: var(--portal-text-12); color: var(--portal-ghost); }

/* The look-book band: one wide photograph, the width of the page, with its
   caption on the rule beneath it. Nothing sits beside it. */
.portal-lookbook { margin: 3rem 0 0; }
.portal-lookbook img {
  width: 100%;
  height: 26rem;
  object-fit: cover;
  display: block;
  background: var(--portal-panel);
}
.portal-lookbook figcaption {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  margin-top: 0.75rem;
  font-size: var(--portal-text-13);
  color: var(--portal-muted);
}

/* ---------------------------------------------------------------- footer */

.portal-footer {
  padding: 1.25rem var(--portal-gutter);
  border-top: 1px solid var(--portal-rule);
  font-size: var(--portal-text-11);
  color: var(--portal-faint);
}
.portal-footer p {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  width: 100%;
  max-width: var(--portal-measure);
  margin: 0 auto;
}

/* -------------------------------------------------------- the price list

   Rows and hairlines, like everything else here: no cards, no zebra. The two
   price columns sit hard right against each other so a margin is read in one
   glance, and they are tabular figures so the digits line up down the column. */

/* A row on Home that leads somewhere -- the module has opened -- reads as a
   link on hover; the ones still to come are plain divs and stay inert. */
a.portal-row:hover .portal-row-name,
a.portal-row:hover .portal-row-state { color: var(--portal-muted); }

.portal-browse {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 2rem 2.5rem;
  margin: 0 0 3rem;
  padding-bottom: 2rem;
  border-bottom: 1px solid var(--portal-rule-strong);
}
.portal-browse .portal-field { margin: 0; min-width: 14rem; }
.portal-browse-actions { display: flex; align-items: center; gap: 1.5rem; }
.portal-browse .portal-button { height: var(--portal-control); }

.portal-price-source { margin: 0.75rem 0 0; font-size: var(--portal-text-13); color: var(--portal-muted); }
.portal-price-source--waiting { color: var(--portal-danger); }

.portal-price-group { margin-top: 3rem; }
.portal-price-type {
  margin: 1.5rem 0 0.5rem;
  font-size: var(--portal-text-18);
}

/* Wide content scrolls inside its own box; the page itself never does. */
.portal-scroll { overflow-x: auto; }

/* The Projects and Designs lists are the same table (`projects & designs`, below):
   one look for every list of rows the portal renders. */
.portal-price-table,
.portal-list-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--portal-text-14);
}
.portal-price-table th,
.portal-price-table td,
.portal-list-table th,
.portal-list-table td {
  padding: 0.625rem 1rem 0.625rem 0;
  text-align: left;
  vertical-align: middle;
  border-bottom: 1px solid var(--portal-rule);
}
.portal-price-table thead th,
.portal-list-table thead th {
  font-size: var(--portal-text-10);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--portal-faint);
  border-bottom: 1px solid var(--portal-rule-strong);
  white-space: nowrap;
}
.portal-price-table tbody th,
.portal-list-table tbody th {
  font-weight: 600;
  color: var(--portal-ink);
}
.portal-price-table tbody th a,
.portal-list-table tbody th a { border-bottom: 1px solid var(--portal-rule-strong); }

/* A WLCA rep's search, under the tab's own matches: the other tabs' matches, apart. */
.portal-list-elsewhere {
  margin: 2rem 0 0.5rem;
  font-size: var(--portal-text-14);
  font-weight: 600;
  color: var(--portal-ink);
}

.portal-price-table .portal-price {
  padding-right: 0;
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.portal-price--partner { font-weight: 600; color: var(--portal-ink); }
.portal-price--retail { color: var(--portal-muted); }
.portal-price-unknown { color: var(--portal-ghost); }

/* Greyed, not gone: the cabinet is still there to be read, and the reason it
   cannot be bought today is in the row (US8). */
.portal-price-row--unavailable > * { color: var(--portal-ghost); }

/* Something the Partner user is told, not something they do: a line on the panel's
   own grey, above the table it changes the meaning of. */
.portal-notice {
  margin: 1.25rem 0 0;
  padding: 0.75rem 1rem;
  font-size: var(--portal-text-13);
  color: var(--portal-body);
  background: var(--portal-panel);
}
.portal-price-row--unavailable .portal-cabinet-picture { opacity: 0.35; }
.portal-price-unavailable { text-align: right; font-size: var(--portal-text-13); }

.portal-price-row--chosen > * { background: var(--portal-panel); }
.portal-price-row--total th { font-weight: 600; }
.portal-price-row--total > * { border-bottom: 1px solid var(--portal-rule-strong); }

/* The cabinet's own proportions, in the Color of the Door design, divided
   into the panels its Structure says its face has. The ratio, the fill and
   each panel's place are inline, because all of them come from the row. */
.portal-cabinet-picture {
  position: relative;
  display: inline-block;
  width: 2.25rem;
  max-height: 3rem;
  margin-right: 0.75rem;
  vertical-align: middle;
  background: var(--portal-panel);
  background-size: cover;
  border: 1px solid var(--portal-rule-strong);
}

/* Each panel is drawn as a hairline outline over the Color, so what a Partner user
   sees is the arrangement -- two doors, a drawer above them -- and not a
   second colour scheme of the picture's own. The outline is translucent black
   rather than a portal token, because it sits on whatever the Door design's
   Color is: a fixed ink would vanish on Navy and shout on White. */
.portal-cabinet-panel {
  position: absolute;
  box-sizing: border-box;
  border: 1px solid var(--portal-draw-line);
}
.portal-cabinet-panel--drawer { border-color: var(--portal-edge-hover); }
.portal-cabinet-panel--blind_panel,
.portal-cabinet-panel--open {
  border-style: dashed;
  background: var(--portal-draw-open);
}
.portal-cabinet-panel--toe_kick { background: var(--portal-draw-toe-kick); }
.portal-cabinet-panel--rail { border-style: solid; }
.portal-cabinet-picture-large { margin: 0 0 1rem; }
.portal-cabinet-picture-large .portal-cabinet-picture {
  width: 11rem;
  max-height: 15rem;
  margin: 0;
}

/* ---------------------------------------------------------- projects & designs

   My projects, a Project's screen and a Design's home. The table is the price list's,
   so what is here is only what these screens have of their own: a Snapshot in
   the first column, the actions on a row, and the project read as facts. */

/* Where a Design's Snapshot goes. Fixed size whether there is a picture or
   not, so the list does not jump about as Snapshots arrive. */
.portal-row-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.75rem 1.5rem;
  margin: 1.5rem 0 0;
}
.portal-list-table .portal-row-actions { margin: 0; }
.portal-row-actions form { margin: 0; }
/* A row's own actions sitting above a section of their own -- a Project's, above
   the section listing its Designs -- need air, or the two rows of small caps
   read as one. */
.portal-row-actions + .portal-section-head { margin-top: 2.75rem; }

/* An action on a row: the underlined word, not a pill. The black pill is for
   the one thing a screen is for -- New design, Start this design. */
.portal-inline-button {
  padding: 0;
  font-family: inherit;
  font-size: var(--portal-text-13);
  color: var(--portal-muted);
  background: none;
  border: 0;
  border-bottom: 1px solid var(--portal-rule-strong);
  cursor: pointer;
}
.portal-inline-button:hover { color: var(--portal-ink); }
.portal-inline-button--danger {
  color: var(--portal-danger);
  border-bottom-color: var(--portal-danger);
}

/* An action that opens a form before it does anything, and no JavaScript in
   any of it: the summary opens the panel, the button inside it acts. Renaming
   needs a field; deleting cannot be undone, and neither belongs on a stray
   click. */
.portal-disclosure summary,
.portal-danger-disclosure summary {
  font-size: var(--portal-text-13);
  color: var(--portal-muted);
  cursor: pointer;
}
.portal-disclosure summary:hover,
.portal-danger-disclosure summary:hover { color: var(--portal-ink); }
.portal-disclosure > form,
.portal-danger-disclosure > form {
  margin: 0.75rem 0 0;
  padding: 0.875rem 1rem;
  background: var(--portal-panel);
}
.portal-disclosure > form .portal-field { margin: 0 0 1rem; min-width: 11rem; }

/* The one whose panel is the colour of the thing it does. */
.portal-danger-disclosure[open] summary { color: var(--portal-danger); }
.portal-danger-disclosure > form { background: var(--portal-danger-wash); }
.portal-danger-disclosure > form p {
  margin: 0 0 0.625rem;
  font-size: var(--portal-text-13);
  color: var(--portal-danger);
}

/* The project, as facts rather than as a form: a Design's home is read before any
   of it is edited. */
.portal-facts { margin: 0; }
.portal-facts dt {
  font-size: var(--portal-text-10);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--portal-faint);
}
.portal-facts dd {
  margin: 0.375rem 0 1.25rem;
  padding-bottom: 1.25rem;
  font-size: var(--portal-text-15);
  color: var(--portal-body);
  border-bottom: 1px solid var(--portal-rule);
}
.portal-facts dd:last-of-type { margin-bottom: 2rem; border-bottom: 0; }

/* A screen's other actions, folded into one word. `details` opens it, so the
   menu needs no JavaScript and closes itself on Escape like any disclosure. */
.portal-menu { position: relative; }
.portal-menu > summary {
  font-size: var(--portal-text-13);
  color: var(--portal-muted);
  cursor: pointer;
  white-space: nowrap;
}
.portal-menu > summary:hover { color: var(--portal-ink); }
.portal-menu-panel {
  position: absolute;
  z-index: 20;
  top: calc(100% + 0.75rem);
  right: 0;
  width: 17rem;
  padding: 1.125rem 1.25rem;
  background: var(--portal-surface);
  border: 1px solid var(--portal-rule-strong);
  text-align: left;
}
/* Stacked in the panel, one action to a line -- the row layout this partial
   wears inside a table would read as a paragraph in here. */
.portal-menu-panel .portal-row-actions {
  flex-direction: column;
  align-items: stretch;
  gap: 0.875rem;
  margin: 0.875rem 0 0;
}
.portal-menu-panel .portal-inline-button,
.portal-menu-panel summary { display: inline-block; }
.portal-menu-panel .portal-quiet { margin: 1rem 0 0; }

/* A panel over the screen, opened by `:target` and closed by the scrim, the
   Close, or the browser's own back -- no JavaScript in any of it. */
.portal-modal {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 60;
  align-items: flex-start;
  justify-content: center;
  padding: 3rem 1.5rem;
  overflow-y: auto;
}
.portal-modal:target { display: flex; }
.portal-modal-scrim {
  position: fixed;
  inset: 0;
  background: var(--portal-scrim-strong);
}
.portal-modal-panel {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 52rem;
  padding: 2rem 2.25rem 2.5rem;
  background: var(--portal-surface);
  border: 1px solid var(--portal-rule-strong);
}
.portal-modal-close {
  position: absolute;
  top: 1.5rem;
  right: 2.25rem;
  font-size: var(--portal-text-12);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--portal-muted);
}
.portal-modal-close:hover { color: var(--portal-ink); }
.portal-modal-panel .portal-price-table { margin-top: 1rem; }

/* ----------------------------------------------------------------- print

   A price list a Partner user hands to a customer: the page and the numbers, and
   none of the chrome that only means something on a screen. */

@media print {
  .portal-header,
  .portal-footer,
  .portal-messages,
  .portal-browse,
  .portal-page-head .portal-quiet { display: none; }

  .portal-main { max-width: none; padding: 0; }
  .portal-scroll { overflow-x: visible; }
  .portal-price-table { font-size: var(--portal-text-12); }
  .portal-price-table tbody th a { border-bottom: 0; }
  /* A cabinet is read as a whole or on the next page, never split in half. */
  .portal-price-table tr,
  .portal-price-group { break-inside: avoid; }
  .portal-price-table thead { display: table-header-group; }
}

/* ---------------------------------------------------------------- narrow */

@media (max-width: 64rem) {
  :root { --portal-gutter: 2rem; }
  .portal-auth { grid-template-columns: minmax(0, 1fr); }
  /* The kitchen is atmosphere, not information: it goes first on a phone. */
  .portal-auth-view { order: -1; height: 14rem; }
  .portal-auth-sheet { padding: 2rem 2rem 2.5rem; }
  .portal-auth-body h1 { font-size: var(--portal-text-44); }
  .portal-split { gap: 2.5rem; grid-template-columns: minmax(0, 1fr); }
  .portal-lookbook img { height: 18rem; }
  h1 { font-size: var(--portal-text-40); }
}

/* Short of room for the function beside the logo and a long Partner name (a tablet, a
   narrow window), the function takes its own line under the logo, its tabs scrolling
   sideways. */
@media (max-width: 60rem) {
  .portal-header { flex-wrap: wrap; gap: 1rem 1.5rem; }
  .portal-function { order: 3; width: 100%; margin-left: 0; padding-left: 0; border-left: 0; flex-wrap: wrap; }
  .portal-partner-menu { margin-left: auto; }
}

@media (max-width: 46rem) {
  .portal-user { display: none; }
  .portal-auth-fields { grid-template-columns: minmax(0, 1fr); gap: 2rem; }
  .portal-auth-actions, .portal-form-actions { flex-wrap: wrap; gap: 1rem 1.5rem; }
  .portal-page-head { flex-direction: column; align-items: flex-start; gap: 1.25rem; }
  /* The head's actions move to the left edge on a phone, and the menu that
     hangs off them has to hang the same way or it opens off the screen. The
     Partner's menu stays at the right edge, where its name is. */
  .portal-menu-panel { width: min(17rem, calc(100vw - 4rem)); }
  .portal-page-head .portal-menu-panel { right: auto; left: 0; }
  .portal-modal { padding: 1.5rem 1rem; }
  .portal-modal-panel { padding: 1.5rem 1.25rem 2rem; }
  .portal-modal-close { top: 1.25rem; right: 1.25rem; }
  .portal-row { flex-wrap: wrap; gap: 0.5rem 1rem; }
  .portal-row-name { width: auto; }
  .portal-row-note { flex-basis: 100%; }
  .portal-footer p, .portal-auth-foot { flex-direction: column; align-items: flex-start; gap: 0.5rem; }
}

/* -- A Project's designs, as cards -------------------------------------------
   One card per option (slice 47): the Snapshot, the name, the Retail total,
   when it was last edited and the newest PDF. The whole card opens the
   Planner -- the name's link is stretched over it -- and everything else sits
   in the menu in its corner, above that stretched link. */
.portal-design-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
  gap: 1.25rem;
  margin: 1.5rem 0 0;
}
.portal-design-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
  padding: 1.25rem;
  border: 1px solid var(--portal-rule);
  background: var(--portal-surface, transparent);
}
.portal-design-card:hover { border-color: var(--portal-rule-strong); }
.portal-design-card-body { display: flex; flex-direction: column; gap: 0.375rem; }
/* The right padding keeps the name's corner clear of the Actions menu, which
   is lifted out of the flow so it sits above the stretched link. The name is
   the one line that reaches the top of the card, so it is the one that would
   otherwise run under it. */
.portal-design-card-name { margin: 0; padding-right: 5rem; font-size: var(--portal-text-16); }
.portal-design-card-open { color: inherit; text-decoration: none; }
/* What makes the whole card the link, without wrapping an anchor round the
   menu's buttons. */
.portal-design-card-open::after { position: absolute; inset: 0; content: ""; }
.portal-design-card-open:hover { text-decoration: underline; }
.portal-design-card-total { margin: 0; font-size: var(--portal-text-14); color: var(--portal-body); }
.portal-design-card-meta { margin: 0; font-size: var(--portal-text-13); color: var(--portal-faint); }
/* Above the stretched link, so it downloads the PDF rather than opening the
   room. */
.portal-design-card-export { position: relative; z-index: 1; margin: 0; font-size: var(--portal-text-13); }
/* What a WLCA rep reads of a Lead's Designs without the Planner (crm ADR 0009): a
   read-only card's PDFs and snapshots, and the Lead page's Designs under each Project. */
.portal-design-card-downloads { margin: 0; padding: 0; list-style: none; font-size: var(--portal-text-13); }
/* An Export the design has moved on from (slice 49, US88): read beside the
   link it warns about, so nobody sends last week's kitchen. */
.portal-design-card-stale {
  margin-left: 0.375rem;
  padding: 0.0625rem 0.375rem;
  border-radius: var(--portal-pill);
  background: var(--portal-danger-wash);
  color: var(--portal-danger);
  font-size: var(--portal-text-11);
}
.portal-design-card-menu { position: absolute; top: 1rem; right: 1rem; z-index: 1; }
.portal-design-card-menu .portal-menu-panel { right: 0; }

/* A Lead whose next To-do is late (crm slice 01): the row and its date stand out. */
.portal-lead-late { background: var(--portal-danger-wash); }
.portal-late { color: var(--portal-danger); font-weight: 600; }

/* A Lead's Stage bar (crm): one segment per Stage, the last one Won or Lost.
   Passed Stages are filled, the current one is filled and named in ink, the
   rest stay grey. Segments wrap to a second row on a phone. */
.portal-stage-bar {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(6.5rem, 1fr));
  gap: 1rem 0.375rem;
  margin: 0 0 2.5rem;
  padding: 0;
  list-style: none;
}
.portal-stage-step {
  padding-top: 0.625rem;
  border-top: 4px solid var(--portal-rule-strong);
  font-size: var(--portal-text-10);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--portal-faint);
  overflow-wrap: anywhere;
}
.portal-stage-step.is-passed { border-top-color: var(--portal-ink); color: var(--portal-muted); }
.portal-stage-step.is-current { border-top: 8px solid var(--portal-ink); margin-top: -4px; color: var(--portal-ink); font-weight: 600; }
.portal-stage-step.is-won { border-top: 8px solid var(--portal-positive); margin-top: -4px; color: var(--portal-positive); font-weight: 600; }
.portal-stage-step.is-lost { border-top: 8px solid var(--portal-danger); margin-top: -4px; color: var(--portal-danger); font-weight: 600; }

/* Air between a table and the heading of the next section. */
.portal-scroll + .portal-section-head { margin-top: 2.75rem; }
/* Scorecards: a column per figure, each heading long; they wrap rather than push the
   table sideways. */
.portal-scorecard-table thead th { white-space: normal; vertical-align: bottom; }

/* Privacy and repeats (crm slice 06). A masked contact reads as a note, not a value;
   a repeat's actions sit in its line, and a POST button there looks like a link. */
.portal-masked { color: var(--portal-faint); font-style: italic; }
.portal-repeats { margin: 0 0 1.5rem; }
.portal-repeats p { margin: 0 0 0.5rem; }
.portal-repeats ul { margin: 0; padding-left: 1.25rem; }
.portal-repeats li { margin: 0.25rem 0; }
.portal-inline-form { display: inline; margin-left: 0.5rem; }
.portal-link-button { padding: 0; border: 0; background: none; color: inherit; font: inherit; text-decoration: underline; cursor: pointer; }

/* ------------------------------------------------------------------- crm

   The Sales desk is worked all day, so its screens trade the showroom for a working
   look: the same fonts, header and black on white, but each subject in its own
   bordered panel, and colour only where it means something: a Stage, a clock running
   out, Won and Lost. Every rule hangs off `.portal-crm`, which `crm/desk_base.html`
   sets on `body`, or off a `portal-crm-*` class only the CRM's templates use. */

.portal-crm {
  --crm-line: var(--portal-rule);
  --crm-edge: var(--portal-rule-strong);
  --crm-label: var(--portal-ink);
  --crm-quiet: var(--portal-muted);
  --crm-radius: var(--portal-radius);
  --crm-head: var(--portal-head);
  --crm-amber: var(--portal-amber);
  --crm-amber-wash: var(--portal-amber-wash);
  --crm-teal: var(--portal-teal);
}

/* A working screen uses the whole window: the page runs edge to edge inside the same
   gutters as the header, so its edges line up with the logo and the Partner menu. */
.portal-crm .portal-main,
.portal-crm .portal-messages { max-width: none; }
/* Messages sit flush above the white band rather than under it. */
.portal-crm .portal-messages { margin-bottom: 0; }

/* A form screen and a Scorecard read as one column, not the full width. */
.portal-crm .portal-crm-column { max-width: 40rem; }

/* --- The head: the title and actions, ruled off from the rest (the tabs are in the header). */

.portal-crm h1 { font-size: var(--portal-text-30); }
.portal-crm-head { margin: -1.75rem 0 1.25rem; }
.portal-crm-head .portal-page-head { margin-bottom: 1.25rem; }
.portal-crm-title { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.875rem; min-width: 0; }
.portal-crm-title h1 { margin: 0; }
/* A record's way back to the list it was opened from (crm/partials/desk_back.html). */
.portal-crm-back { flex: none; font-size: var(--portal-text-22); line-height: 1; color: var(--crm-quiet); text-decoration: none; }
.portal-crm-back:hover { color: var(--portal-ink); }
/* A short fact beside the title: why it was Lost, the Response deadline. */
.portal-crm-aside { font-size: var(--portal-text-13); color: var(--crm-quiet); white-space: nowrap; }

/* What the screen is for: a "?" beside the title (crm/partials/screen_help.html). */
/* Small and faint, tucked close to the title. */
.portal-crm-help { position: relative; display: inline-flex; flex: none; margin-left: -0.5rem; opacity: 0.55; }
.portal-crm-help:hover,
.portal-crm-help:focus-within { opacity: 1; }
.portal-crm-help button {
  width: 1rem;
  height: 1rem;
  padding: 0;
  font: 600 var(--portal-text-10)/1 var(--portal-ui);
  color: var(--crm-quiet);
  background: var(--portal-surface);
  border: 1px solid var(--crm-edge);
  border-radius: var(--portal-round);
  cursor: help;
}
.portal-crm-help button:hover,
.portal-crm-help button:focus-visible { color: var(--portal-ink); border-color: var(--portal-ink); }
.portal-crm-help-text {
  position: absolute;
  top: calc(100% + 0.5rem);
  left: 0;
  z-index: 20;
  width: max-content;
  max-width: 22rem;
  padding: 0.625rem 0.75rem;
  font-size: var(--portal-text-12);
  font-weight: 400;
  line-height: 1.5;
  white-space: normal;
  color: var(--portal-surface);
  background: var(--portal-ink);
  border-radius: var(--portal-radius);
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.12s;
}
.portal-crm-help:hover .portal-crm-help-text,
.portal-crm-help:focus-within .portal-crm-help-text { visibility: visible; opacity: 1; }

/* --- Buttons: squared and sentence case, sized for a toolbar. The black button is
   the screen's next step; `portal-crm-action` is every other one, link or button,
   outlined, and green for Won, red for Lost. */

.portal-crm .portal-button,
.portal-crm-action {
  height: var(--portal-control-sm);
  padding: 0 1.125rem;
  font-size: var(--portal-text-13);
  letter-spacing: 0;
  text-transform: none;
  border-radius: var(--portal-radius);
}
.portal-crm-action {
  display: inline-flex;
  align-items: center;
  font-family: var(--portal-ui);
  font-weight: 600;
  color: var(--portal-ink);
  text-decoration: none;
  background: var(--portal-surface);
  border: 1px solid var(--crm-edge);
  cursor: pointer;
}
.portal-crm-action:hover { color: var(--portal-ink); border-color: var(--portal-ink); }
/* A Lead page's rarer moves (Give to a Partner, Make Partner, Claim back) behind a small ⋯ beside its
   Stage buttons (crm/lead_detail.html), the same height as they are. */
.portal-lead-menu > summary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: var(--portal-control-sm);
  font-size: var(--portal-text-18);
  color: var(--portal-ink);
  list-style: none;
  background: var(--portal-surface);
  border: 1px solid var(--crm-edge);
  border-radius: var(--portal-radius);
}
.portal-lead-menu > summary::-webkit-details-marker { display: none; }
.portal-lead-menu > summary:hover,
.portal-lead-menu[open] > summary { border-color: var(--portal-ink); }
.portal-lead-menu .portal-add-menu-item { text-decoration: none; }
.portal-crm-action.is-lost { color: var(--portal-danger); border-color: var(--portal-danger); }
.portal-crm .portal-page-head-actions { gap: 0.625rem; flex-wrap: wrap; }
.portal-crm .portal-page-head-actions form { margin: 0; }

/* --- Colour that means something. */

/* A Stage as a tag (crm/partials/stage_tag.html): each its own colour, and each colour
   also its own lightness. */
.portal-stage-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.125rem 0.625rem;
  font-size: var(--portal-text-12);
  font-weight: 600;
  line-height: 1.6;
  white-space: nowrap;
  border-radius: var(--portal-radius);
  color: var(--portal-stone);
  background: var(--portal-stone-wash);
}
.portal-stage-tag::before { content: ""; width: 7px; height: 7px; border-radius: var(--portal-round); background: currentColor; }
.portal-stage-tag.is-new { color: var(--portal-blue); background: var(--portal-blue-wash); }
.portal-stage-tag.is-contacted { color: var(--crm-teal); background: var(--portal-teal-wash); }
.portal-stage-tag.is-designing { color: var(--portal-purple); background: var(--portal-purple-wash); }
.portal-stage-tag.is-quoted { color: var(--crm-amber); background: var(--crm-amber-wash); }
.portal-stage-tag.is-won { color: var(--portal-positive); background: var(--portal-positive-wash); }
.portal-stage-tag.is-lost { color: var(--portal-stone); background: var(--portal-stone-wash); }

/* Working time left on a Response deadline: amber while it runs, red once it is up. */
.portal-time-left {
  display: inline-block;
  padding: 0.125rem 0.5rem;
  font-size: var(--portal-text-12);
  font-weight: 600;
  white-space: nowrap;
  color: var(--crm-amber);
  background: var(--crm-amber-wash);
  border-radius: var(--portal-radius);
}
.portal-time-left.is-up { color: var(--portal-danger); background: var(--portal-danger-tint); }

/* A Stage bar as a progress bar (crm/partials/stage_bar.html): short, on the left, a
   thin segment per Stage over its name. */
.portal-crm .portal-stage-bar {
  grid-template-columns: repeat(auto-fit, minmax(5.5rem, 1fr));
  gap: 0.5rem 3px;
  max-width: 34rem;
  margin: 0 0 1.5rem;
}
.portal-crm .portal-stage-step {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: var(--portal-text-12);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--crm-quiet);
}
.portal-crm .portal-stage-step::before {
  content: "";
  display: block;
  height: 6px;
  margin-bottom: 0.375rem;
  border-radius: var(--portal-radius);
  background: var(--crm-edge);
}
.portal-crm .portal-stage-step.is-passed::before,
.portal-crm .portal-stage-step.is-current::before { background: var(--crm-teal); }
.portal-crm .portal-stage-step.is-current { color: var(--crm-teal); font-weight: 700; }
.portal-crm .portal-stage-step.is-won { color: var(--portal-positive); font-weight: 700; }
.portal-crm .portal-stage-step.is-won::before { background: var(--portal-positive); }
.portal-crm .portal-stage-step.is-lost { color: var(--portal-danger); font-weight: 700; }
.portal-crm .portal-stage-step.is-lost::before { background: var(--portal-danger); }

/* --- Tables sit in a white panel, their heads on a band. */

.portal-crm .portal-scroll {
  margin-bottom: 1.5rem;
  background: var(--portal-surface);
  border: 1px solid var(--crm-edge);
  border-radius: var(--crm-radius);
}
.portal-crm .portal-list-table th,
.portal-crm .portal-list-table td { padding: 0.625rem 0.875rem; border-bottom-color: var(--crm-line); }
.portal-crm .portal-list-table thead th {
  font-size: var(--portal-text-11);
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--crm-label);
  background: var(--crm-head);
  border-bottom: 0;
  /* The rule is drawn inside the cell: a collapsed border stays behind when it sticks. */
  box-shadow: inset 0 -1px 0 var(--crm-edge);
}
.portal-crm .portal-list-table tbody tr:last-child > * { border-bottom: 0; }
.portal-crm .portal-list-table tbody th a { border-bottom: 0; }
.portal-crm .portal-list-table tbody th a:hover { text-decoration: underline; color: var(--portal-ink); }
.portal-crm .portal-late { margin-left: 0.375rem; }

/* Section heads between tables, and the head of a card: a label in small capitals. */
.portal-crm .portal-section-head { margin: 0 0 0.625rem; align-items: center; }
.portal-crm .portal-scroll + .portal-section-head { margin-top: 1rem; }
.portal-crm .portal-section-head h2,
.portal-crm-card-head,
.portal-crm-card-head h2 {
  margin: 0;
  font-family: var(--portal-ui);
  font-size: var(--portal-text-12);
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--crm-label);
}
.portal-crm .portal-section-head p { margin: 0; font-size: var(--portal-text-13); color: var(--crm-quiet); }

/* --- A card: one subject in a panel, a head on a band, then its rows. */

.portal-crm-card {
  margin-bottom: 1.25rem;
  background: var(--portal-surface);
  border: 1px solid var(--crm-edge);
  border-radius: var(--crm-radius);
  overflow: hidden;
}
.portal-crm-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.75rem 1rem;
  background: var(--crm-head);
  border-bottom: 1px solid var(--crm-edge);
}
.portal-crm-card-head form { margin: 0; }
.portal-crm-card-head .portal-inline-button { font-size: var(--portal-text-12); font-weight: 600; letter-spacing: 0; text-transform: none; color: var(--portal-ink); }
.portal-crm-card-body { padding: 1rem; font-size: var(--portal-text-13); }
.portal-crm-card-body > * { margin: 0 0 1rem; }
.portal-crm-card-body > :last-child { margin-bottom: 0; }
.portal-crm-card-body .portal-quiet { margin: 0.375rem 0 0; }
.portal-crm-empty { margin: 0; padding: 0.875rem 1rem; }

/* A Lead's Projects (crm/partials/lead_projects.html): each Project in two lanes, its Designs then
   its Quotes, an arrow between them where a Design made a Quote. */
.portal-project { padding: 1rem; border-bottom: 1px solid var(--crm-line); }
.portal-project:last-child { border-bottom: 0; }
.portal-project-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 0.75rem; margin-bottom: 0.75rem; }
.portal-project-head h3 { margin: 0; font-family: var(--portal-display); font-size: var(--portal-text-20); font-weight: 400; }
.portal-project-head h3 a { color: var(--portal-ink); text-decoration: none; }
.portal-project-head h3 a:hover { text-decoration: underline; }
.portal-project-actions { display: flex; gap: 1rem; margin-left: auto; }
.portal-project-actions form { margin: 0; }
.portal-project-actions .portal-inline-button { font-weight: 600; color: var(--portal-ink); }
.portal-project-lanes { display: grid; grid-template-columns: minmax(0, 1fr) 2.5rem minmax(0, 1.25fr); align-items: start; }
.portal-project-lane { display: flex; flex-direction: column; gap: 0.5rem; min-width: 0; }
.portal-project-lane h4 { margin: 0; font-size: var(--portal-text-12); font-weight: 600; color: var(--crm-quiet); }
.portal-project-arrow { display: flex; justify-content: center; padding-top: 2.25rem; color: var(--crm-teal); }
.portal-project-item {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.625rem 0.75rem;
  font-size: var(--portal-text-13);
  color: var(--portal-ink);
  text-decoration: none;
  border: 1px solid var(--crm-edge);
  border-radius: var(--crm-radius);
}
a.portal-project-item:hover { border-color: var(--portal-ink); }
a.portal-project-item:focus-visible { outline: 2px solid var(--portal-ink); outline-offset: 2px; }
.portal-project-item-line { display: flex; align-items: baseline; gap: 0.625rem; }
.portal-project-item-name { font-weight: 600; }
.portal-project-amount { margin-left: auto; font-weight: 600; white-space: nowrap; }
.portal-project-meta { font-size: var(--portal-text-12); color: var(--crm-quiet); }
.portal-project-empty { margin: 0; padding: 0.625rem 0.75rem; font-size: var(--portal-text-13); color: var(--crm-quiet); border: 1px dashed var(--crm-edge); border-radius: var(--crm-radius); }
.portal-project-status { padding: 0.0625rem 0.5rem; font-size: var(--portal-text-11); font-weight: 600; color: var(--crm-teal); background: var(--portal-teal-wash); border-radius: var(--portal-radius); }
.portal-project-status--draft { color: var(--portal-body); background: var(--portal-panel); }
.portal-project-status--confirmed { color: var(--portal-surface); background: var(--crm-teal); }
.portal-project-status--declined,
.portal-project-status--expired { color: var(--portal-danger); background: var(--portal-danger-wash); }
.portal-project-earlier { margin: 0.25rem 0 0; font-size: var(--portal-text-12); color: var(--crm-quiet); }
.portal-project-earlier summary { padding: 0.25rem 0.75rem; cursor: pointer; }
.portal-project-earlier ul { margin: 0; padding: 0.25rem 0.75rem; list-style: none; }
.portal-project-earlier li { padding: 0.125rem 0; }
/* A sent Quote's PDF, a small link under its row, beside the earlier Revisions (crm slice 35). */
.portal-project-quote-pdf { display: inline-block; padding: 0.125rem 0.75rem; font-size: var(--portal-text-12); color: var(--crm-quiet); }
.portal-project-quote-pdf:hover { color: var(--portal-ink); }
/* A narrow column stacks the lanes; the arrow then has nowhere to point. */
@media (max-width: 40rem) {
  .portal-project-lanes { grid-template-columns: minmax(0, 1fr); gap: 1rem; }
  .portal-project-arrow { display: none; }
}

/* A Project's own screen (planner/project_detail.html): three columns, Designs, Quotes and
   Order, under a head each. Every Design is a row, the Quotes made from it beside it and
   the Order beside the Quote it follows: each row and its Quotes take the columns as a
   subgrid, so a Quote lines up with its Design and an Order with its Quote. One column
   on a narrow window. A design card's Actions menu hangs out of its card, so nothing
   clips. */
.portal-project-page-lanes {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0 1rem;
  align-items: start;
}
.portal-project-board-head { border: 1px solid var(--crm-edge); border-radius: var(--crm-radius); }
.portal-project-board-row,
.portal-project-board-quotes { display: grid; grid-template-columns: subgrid; row-gap: 0.75rem; }
.portal-project-board-row { grid-column: 1 / -1; padding: 0.75rem 0; border-bottom: 1px solid var(--crm-line); }
.portal-project-board-design { grid-column: 1; min-width: 0; }
.portal-project-board-quotes { grid-column: 2 / -1; }
.portal-project-board-quote,
.portal-project-board-order { min-width: 0; }
/* The cards of one row stand as tall as each other: a Design as tall as its Quotes, a
   Quote as tall as the Order beside it. Here a Quote's border takes in its PDF link and
   earlier Revisions too, so its whole card stretches. */
.portal-project-board-design,
.portal-project-board-quote,
.portal-project-board-order,
.portal-project-board-quote > .portal-project-quote { display: flex; flex-direction: column; }
.portal-project-board-design > .portal-design-card,
.portal-project-board-quote > .portal-project-quote,
.portal-project-board-quote .portal-project-quote > .portal-project-item,
.portal-project-board-order > .portal-order-card { flex: 1 1 auto; }
.portal-project-board-quote .portal-project-quote { border: 1px solid var(--crm-edge); border-radius: var(--crm-radius); }
.portal-project-board-quote .portal-project-quote:has(> a.portal-project-item:hover) { border-color: var(--portal-ink); }
.portal-project-board-quote .portal-project-item { border: 0; }
.portal-project-board-quote .portal-project-quote-pdf {
  align-self: flex-start;
  margin: 0 0.75rem 0.625rem;
  padding: 0.125rem 0.625rem;
  font-weight: 600;
  color: var(--portal-ink);
  text-decoration: none;
  border: 1px solid var(--crm-edge);
  border-radius: var(--portal-radius);
}
.portal-project-board-quote .portal-project-quote-pdf:hover { border-color: var(--portal-ink); }
.portal-project-board-order.is-alone { grid-column: 3; }
.portal-project-board-typed { margin: 0; padding: 0.625rem 0; }
.portal-project-board-note { grid-column: 1; margin: 0.75rem 0 0; }
.portal-project-page-lanes .portal-design-card { border-radius: var(--crm-radius); }
.portal-project-page-lanes .portal-project-empty > p { margin: 0 0 0.75rem; }
.portal-project-page-lanes .portal-project-lane > * { margin: 0; }
.portal-order-card { padding: 0.75rem; border: 1px solid var(--crm-edge); border-radius: var(--crm-radius); }
/* A heading for whoever cannot see the columns it sits in. */
.portal-hidden-title { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* A Project's Files card (planner/partials/project_files.html, crm slice 41): the kinds as
   tabs, the add form, then a grid of thumbnails; a document shows its type in the tile. */
.portal-project-files { margin-top: 1.5rem; }
.portal-project-files.is-dropping { outline: 2px dashed var(--crm-teal); outline-offset: -4px; }
.portal-project-files .portal-subtabs { flex-wrap: wrap; }
.portal-file-add { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.75rem; margin: 0 0 1rem; }
.portal-file-add .portal-form-errors { flex-basis: 100%; color: var(--portal-danger); }
.portal-file-kind-pick { display: inline-flex; align-items: center; gap: 0.5rem; font-size: var(--portal-text-14); }
.portal-file-pick { position: relative; cursor: pointer; }
.portal-file-pick input[type="file"] { position: absolute; inset: 0; width: 100%; opacity: 0; cursor: pointer; }
.portal-file-drop-hint { flex-basis: 100%; margin: 0; }
@media (hover: hover) and (pointer: fine) { .portal-file-camera { display: none; } }
.portal-project-file-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: 0.75rem; margin: 0; padding: 0; list-style: none; }
.portal-project-file { display: flex; flex-direction: column; min-width: 0; border: 1px solid var(--crm-line); border-radius: var(--crm-radius); overflow: hidden; }
.portal-project-file-thumb { display: flex; align-items: center; justify-content: center; aspect-ratio: 4 / 3; background: var(--portal-panel); color: var(--portal-muted); font-weight: 600; text-decoration: none; }
.portal-project-file-thumb img { width: 100%; height: 100%; object-fit: cover; }
.portal-project-file-about { display: flex; flex-direction: column; gap: 0.25rem; padding: 0.5rem 0.625rem; font-size: var(--portal-text-13); }
.portal-project-file-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.portal-project-file-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem 0.75rem; }
.portal-project-file-actions form { display: inline-flex; align-items: center; gap: 0.375rem; margin: 0; }
@media (max-width: 56rem) {
  .portal-project-page-lanes { grid-template-columns: minmax(0, 1fr); row-gap: 0.5rem; }
  .portal-project-board-row,
  .portal-project-board-quotes { grid-column: 1; }
  .portal-project-board-order.is-alone { grid-column: 1; }
}

/* The way up from a Quote or a Design (planner/partials/project_trail.html): the Lead, then
   the Project, whose menu reaches its other Designs and Quotes and the Lead's other Projects. */
.portal-trail { display: flex; flex: 0 1 auto; align-items: center; gap: 0.375rem; min-width: 0; font-size: var(--portal-text-13); white-space: nowrap; }
.portal-trail a { color: var(--portal-muted); text-decoration: none; }
.portal-trail a:hover { color: var(--portal-ink); text-decoration: underline; }
.portal-trail-lead { display: inline-flex; align-items: center; gap: 0.375rem; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.portal-trail-lead svg { flex: none; }
.portal-trail-split { color: var(--portal-faint); }
.portal-trail-project { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.portal-column-menu.portal-revisions-menu { width: 18rem; }
.portal-revisions-menu ul { margin: 0; padding: 0; list-style: none; }
.portal-revisions-menu li { display: flex; justify-content: space-between; gap: 0.75rem; padding: 0.25rem 0; }
.portal-revisions-menu li span { color: var(--portal-faint); }
.portal-revisions-menu [aria-current] { font-weight: 600; color: var(--portal-ink); }
.portal-crm-aside .portal-column-button { margin: 0; padding: 0; font: inherit; color: inherit; }

/* --- Facts read as a record: labels are row heads in semibold, values in plain text. */

.portal-crm .portal-facts {
  display: grid;
  grid-template-columns: minmax(8rem, 34%) minmax(0, 1fr);
  margin-bottom: 1.25rem;
  background: var(--portal-surface);
  border: 1px solid var(--crm-edge);
  border-radius: var(--crm-radius);
  overflow: hidden;
}
.portal-crm .portal-facts dt,
.portal-crm .portal-facts dd {
  margin: 0;
  padding: 0.625rem 0.875rem;
  font-size: var(--portal-text-13);
  border-bottom: 1px solid var(--crm-line);
}
.portal-crm .portal-facts dt {
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--crm-label);
  border-right: 1px solid var(--crm-line);
}
.portal-crm .portal-facts dd { font-weight: 400; color: var(--portal-body); }
.portal-crm .portal-facts dd:last-of-type,
.portal-crm .portal-facts dt:last-of-type { margin: 0; border-bottom: 0; }
.portal-crm-card .portal-facts { margin: 0; border: 0; border-radius: 0; }

/* --- Forms sit in a panel; inside a card the card is the panel. */

.portal-crm .portal-form {
  padding: 1.5rem;
  background: var(--portal-surface);
  border: 1px solid var(--crm-edge);
  border-radius: var(--crm-radius);
}
.portal-crm .portal-form + .portal-scroll,
.portal-crm .portal-form + .portal-lede { margin-top: 1.25rem; }
.portal-crm .portal-form-actions { margin-top: 1.5rem; }
/* What to fill in, at the top of a form screen's panel. */
.portal-crm-intro { margin: 0 0 1.25rem; font-size: var(--portal-text-13); line-height: 1.6; color: var(--crm-quiet); }
.portal-crm-card .portal-form { max-width: none; margin: 0; padding: 1rem; border: 0; border-bottom: 1px solid var(--crm-line); border-radius: 0; }
.portal-crm-card .portal-form:last-child { border-bottom: 0; }
.portal-crm-card .portal-form .portal-field { margin-bottom: 0.75rem; }
.portal-crm-card .portal-form .portal-form-actions { margin-top: 0; justify-content: flex-end; }
.portal-crm .portal-split { gap: 1.25rem; }

/* --- On a wide screen the top of a CRM screen stays put while the rest scrolls: the
   portal header with the desk's tabs, then the title row, then a table's column heads.
   Each band gets a fixed height so the next knows where to stop, and the bands are
   kept short: one line of title beside its actions. Narrower, the
   bands wrap and everything scrolls away, and a table scrolls sideways with its heads. */

@media (min-width: 64rem) {
  .portal-crm {
    --crm-header-height: 4.75rem;
    --crm-title-height: 3.75rem;
    --crm-gap: 1.25rem;
  }
  /* The header and the title read as one white block, edge to edge, with a rule
     under the header and none under the title. */
  .portal-crm .portal-header {
    position: sticky;
    top: 0;
    z-index: 10;
    height: var(--crm-header-height);
    padding-top: 0;
    padding-bottom: 0;
    background: var(--portal-surface);
    border-bottom: 1px solid var(--crm-edge);
  }
  /* Under the title's rule the block keeps a strip of white, so even stuck there is
     air between the title and the first table. */
  .portal-crm-head {
    position: sticky;
    top: var(--crm-header-height);
    z-index: 9;
    margin: -3.5rem 0 0;
    padding-bottom: var(--crm-gap);
    background: var(--portal-surface);
    border-bottom: 0;
  }
  /* The white runs out to both window edges without widening the page.
     It lives on a layer behind the block, so its clip leaves the "?" free to hang
     below. */
  .portal-crm-head::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    z-index: -1;
    clip-path: inset(0 -100vmax);
  }
  .portal-crm-head::before { top: 0; bottom: 0; background: var(--portal-surface); box-shadow: 0 0 0 100vmax var(--portal-surface); }
  .portal-crm-head .portal-page-head {
    height: var(--crm-title-height);
    margin: 0;
    align-items: center;
  }
  .portal-crm-head h1 { font-size: var(--portal-text-24); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* Short of room, the fact beside the title gives way first, then the title. */
  .portal-crm-title { flex-wrap: nowrap; }
  .portal-crm-title h1 { flex: 0 1 auto; min-width: 8rem; }
  .portal-crm-title .portal-stage-tag { flex: none; }
  .portal-crm-title .portal-crm-aside { flex: 0 100 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  .portal-crm .portal-scroll { overflow: clip; }
  .portal-crm .portal-list-table thead th {
    position: sticky;
    /* Flush under the block's strip of white. */
    top: calc(var(--crm-header-height) + var(--crm-title-height) + var(--crm-gap));
    z-index: 1;
  }
}

@media (max-width: 46rem) {
  .portal-crm .portal-facts { grid-template-columns: minmax(0, 1fr); }
  .portal-crm .portal-facts dt { border-right: 0; border-bottom: 0; padding-bottom: 0.25rem; }
  .portal-crm .portal-facts dd { padding-top: 0.25rem; }
}

/* ------------------------------------------------------------ list search

   One box over a Sales desk list (crm/partials/list_search.html): a name, or a
   whole phone number or email. Sent by POST, so a contact never sits in an
   address. */

.portal-search {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1rem;
  margin: 0 0 1.5rem;
}
/* A desk list's toolbar: its search on the left, its New button on the right, on one line. */
.portal-list-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem 1rem; margin: 0 0 1.5rem; }
.portal-list-bar .portal-search { flex: 1 1 28rem; margin: 0; }
.portal-list-bar > .portal-button { margin-left: auto; }
/* The Leads list's Won, not ordered filter (orders slice 12): off, a quiet outline; on, filled. */
.portal-filter-switch {
  display: inline-flex; align-items: center; gap: 0.375rem; height: var(--portal-control-sm); padding: 0 0.875rem;
  font-size: var(--portal-text-14); white-space: nowrap; color: var(--portal-ink); text-decoration: none;
  background: var(--portal-surface); border: 1px solid var(--portal-rule-strong); border-radius: var(--portal-pill);
}
.portal-filter-switch:hover { border-color: var(--portal-ink); }
.portal-filter-switch.is-on { color: var(--portal-surface); background: var(--portal-ink); border-color: var(--portal-ink); }
.portal-filter-switch.is-on::before { content: "\2713"; }
/* A WLCA rep's "Takes Leads in turn" switch (crm slice 40): its state, then the word that flips it. */
.portal-round-switch { display: inline-flex; align-items: center; gap: 0.5rem; margin: 0; font-size: var(--portal-text-14); white-space: nowrap; }
.portal-round-state { font-weight: 600; }
.portal-round-state.is-off { color: var(--portal-muted); }
.portal-search-input {
  flex: 0 1 28rem;
  min-width: 0;
  height: var(--portal-control-sm);
  padding: 0 0.75rem;
  font: inherit;
  font-size: var(--portal-text-14);
  color: var(--portal-ink);
  background: var(--portal-surface);
  border: 1px solid var(--portal-edge);
  border-radius: var(--portal-radius);
}
.portal-search-input:hover { border-color: var(--portal-edge-hover); }
.portal-search-input:focus { border-color: var(--portal-teal); box-shadow: var(--portal-focus-ring); outline: 0; }
.portal-search-input::placeholder { color: var(--portal-faint); }

/* ------------------------------------------------------------ column menus

   Stage, Source and Salesperson on the Leads list each open a menu from their head
   (crm/partials/lead_column_head.html): sort, group, and values to show. The menu
   is a popover, so the table's rounded panel never clips it. */

.portal-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.portal-column-button {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  margin: -0.25rem -0.375rem;
  padding: 0.25rem 0.375rem;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  background: none;
  border: 0;
  border-radius: var(--portal-radius);
  cursor: pointer;
}
.portal-column-button:hover { background: var(--portal-hover); }
.portal-column-caret { font-size: var(--portal-text-10); color: var(--portal-faint); }
.portal-column-mark { font-size: var(--portal-text-12); letter-spacing: 0; color: var(--crm-teal, var(--portal-ink)); }
.portal-column-head.is-active .portal-column-caret { color: var(--portal-ink); }

.portal-column-menu {
  width: 15rem;
  max-height: min(28rem, calc(100vh - 2rem));
  margin: auto;
  padding: 0.875rem 1rem 1rem;
  overflow: auto;
  font: 400 var(--portal-text-13)/1.5 var(--portal-ui);
  letter-spacing: 0;
  text-transform: none;
  color: var(--portal-body);
  background: var(--portal-surface);
  border: 1px solid var(--portal-rule-strong);
  border-radius: var(--portal-radius);
  box-shadow: var(--portal-shadow-menu);
}
/* Placed by crm/js/column-menu.js under its head; otherwise it opens centred. */
.portal-column-menu.is-placed { position: fixed; inset: auto; margin: 0; }
.portal-column-menu-label {
  margin: 0.875rem 0 0.375rem;
  font-size: var(--portal-text-11);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--portal-faint);
}
.portal-column-menu-label:first-child { margin-top: 0; }
.portal-column-choices,
.portal-column-ticks { margin: 0; padding: 0; list-style: none; }
.portal-column-choices a { display: block; padding: 0.25rem 0; }
.portal-column-choices a[aria-current="true"] { font-weight: 600; }
.portal-column-choices a[aria-current="true"]::before { content: "✓ "; }
.portal-group-order { margin: 0; padding: 0 0 0 1.25rem; }
.portal-group-order li { display: flex; align-items: center; gap: 0.375rem; padding: 0.188rem 0; }
.portal-group-order li > span { flex: 1 1 auto; }
.portal-group-order a { padding: 0 0.375rem; border-radius: var(--portal-radius); }
.portal-group-order a:hover { background: var(--portal-hover); }
.portal-column-ticks label { display: flex; align-items: center; gap: 0.5rem; padding: 0.188rem 0; cursor: pointer; }
.portal-column-ticks input { margin: 0; accent-color: var(--portal-ink); }
.portal-column-menu-actions {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1rem;
  padding-top: 0.875rem;
  border-top: 1px solid var(--portal-rule);
}
.portal-column-close { margin-left: auto; padding: 0; background: none; border: 0; cursor: pointer; font: inherit; }

/* Small tabs inside one screen (the Leads list's My Leads / All Leads). */
.portal-subtabs { display: flex; gap: 0.25rem; margin: 0 0 1rem; }
.portal-subtabs a {
  padding: 0.25rem 0.75rem;
  border-radius: var(--portal-pill);
  font-size: var(--portal-text-13);
  font-weight: 500;
  color: var(--portal-muted);
}
.portal-subtabs a:hover { color: var(--portal-ink); }
.portal-subtabs a[aria-current="page"] { font-weight: 600; color: var(--portal-ink); background: var(--portal-panel); }
.portal-view-summary { display: flex; flex-wrap: wrap; gap: 0.25rem 1rem; margin: -0.75rem 0 0.75rem; font-size: var(--portal-text-13); color: var(--portal-muted); }

/* A grouped list: each band opens with what its rows share, and how many there are. */
.portal-crm .portal-list-table .portal-group-row th {
  font-size: var(--portal-text-12);
  font-weight: 600;
  color: var(--portal-ink);
  background: var(--portal-raised);
  border-top: 1px solid var(--crm-edge);
}
.portal-crm .portal-list-table tbody:first-of-type .portal-group-row.is-depth-0 th { border-top: 0; }
.portal-group-count { margin-left: 0.375rem; font-weight: 400; color: var(--portal-muted); }
/* Groups inside groups (`is-nested`): the outermost head stands out most, each deeper one is stepped
   in under the head it sits in, and quieter. */
.portal-crm .portal-list-table.is-nested .portal-group-row.is-depth-0 th { font-size: var(--portal-text-13); background: var(--portal-head); }
.portal-crm .portal-list-table .portal-group-row.is-depth-1 th { padding-left: 2rem; background: var(--portal-raised); border-top-color: var(--crm-line); }
.portal-crm .portal-list-table .portal-group-row.is-depth-2 th { padding-left: 3.25rem; font-weight: 500; background: var(--portal-surface); border-top-color: var(--crm-line); }
.portal-crm .portal-list-table .portal-group-row.is-depth-3 th,
.portal-crm .portal-list-table .portal-group-row.is-depth-4 th { padding-left: 4.5rem; font-weight: 500; background: var(--portal-surface); border-top-color: var(--crm-line); }
.portal-group-toggle {
  display: inline-flex;
  align-items: baseline;
  gap: 0.25rem;
  padding: 0;
  background: none;
  border: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: default;
}
/* Folding needs script; without it the head is a plain label. */
.portal-group-caret { display: none; font-size: var(--portal-text-10); color: var(--portal-faint); transition: transform 0.15s; }
.is-foldable .portal-group-toggle { cursor: pointer; }
.is-foldable .portal-group-caret { display: inline-block; }
.portal-group-toggle[aria-expanded="false"] .portal-group-caret { transform: rotate(-90deg); }
@media (min-width: 64rem) {
  /* The outermost head stays under the column heads while its rows scroll by, and is
     pushed up out of the way when its group ends. */
  body.portal-list-page .portal-lead-table thead th { z-index: 2; }
  body.portal-list-page .portal-lead-table tr.is-depth-0 {
    position: sticky;
    top: var(--lead-heads-height, 2.25rem);
    z-index: 1;
  }
}

/* --- A Lead's page: its details and Projects on the left, its Activities
   in the right two-fifths. */

@media (min-width: 64.0625rem) {
  .portal-record-split { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); }
}

/* The pencil in a card's head that turns the card into a form. */
.portal-card-edit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: var(--portal-control-xs);
  margin: -0.25rem -0.375rem -0.25rem 0;
  color: var(--crm-quiet);
  border-radius: var(--portal-radius);
}
.portal-card-edit:hover { color: var(--portal-ink); background: var(--portal-hover); }

/* An earlier Stage on the bar is a button: clicking it asks why, then moves back. */
.portal-crm .portal-stage-back {
  padding: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  background: none;
  border: 0;
  cursor: pointer;
}
.portal-crm .portal-stage-back:hover,
.portal-crm .portal-stage-back:focus-visible { color: var(--portal-ink); text-decoration: underline; }

/* A pop-up holding one form (crm/partials/pop_up_form.html). crm/js/pop-up.js opens it
   beside the button that opened it; without script it opens centred. */
.portal-pop-up {
  width: min(30rem, calc(100vw - 2rem));
  max-height: calc(100vh - 2rem);
  margin: auto;
  padding: 0;
  overflow: auto;
  color: var(--portal-body);
  background: var(--portal-surface);
  border: 0;
  border-radius: var(--portal-radius-pop);
  box-shadow: var(--portal-shadow-pop);
}
.portal-pop-up::backdrop { background: var(--portal-scrim); }
.portal-pop-up.is-placed { position: fixed; inset: auto; margin: 0; }
.portal-pop-up.is-placing { visibility: hidden; }
.portal-pop-up > .portal-form,
.portal-crm .portal-pop-up .portal-form { max-width: none; margin: 0; padding: 1.375rem 1.5rem 0; border: 0; border-radius: 0; }
/* A title in the display face, one line on what happens, the fields, then a footer with
   Cancel and the one action, always at the bottom right. Short fields that belong
   together (a To-do's date and time) share a row. */
.portal-pop-up .portal-form {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 1rem;
}
.portal-pop-up .portal-form > * { grid-column: 1 / -1; }
.portal-pop-up .portal-form > .portal-field:has(input[type="date"]):has(+ .portal-field input[type="time"]),
.portal-pop-up .portal-form > .portal-field:has(input[type="date"]) + .portal-field:has(input[type="time"]) { grid-column: auto; align-self: end; }
.portal-pop-up .portal-form > .portal-field:has(input[type="date"]):has(+ .portal-field input[type="time"]) { align-self: end; }
@media (max-width: 30rem) {
  .portal-pop-up .portal-form > .portal-field:has(input[type="date"]):has(+ .portal-field input[type="time"]),
  .portal-pop-up .portal-form > .portal-field:has(input[type="date"]) + .portal-field:has(input[type="time"]) { grid-column: 1 / -1; }
}
.portal-pop-up-title { margin: 0 0 0.375rem; font: 400 var(--portal-text-22)/1.25 var(--portal-display); color: var(--portal-ink); }
.portal-pop-up .portal-crm-intro { margin: 0 0 1.25rem; font-size: var(--portal-text-14); line-height: 1.5; color: var(--portal-body); }
.portal-pop-up .portal-pop-up-title + .portal-field,
.portal-pop-up .portal-pop-up-title + input + .portal-field { margin-top: 0.875rem; }
.portal-pop-up .portal-form-actions {
  justify-content: flex-end;
  margin: 1.5rem -1.5rem 0;
  padding: 0.75rem 1.5rem;
  border-top: 1px solid var(--portal-rule);
}
.portal-pop-up-cancel { cursor: pointer; }

/* Activities (crm/partials/activities.html): what to add in the head, a row of kinds to
   narrow by, then one entry each, newest first. */
/* What the Activities card's + offers: one line per kind, its mark coloured as the kind. */
.portal-add-menu { width: auto; min-width: 12rem; padding: 0.375rem; }
.portal-add-menu-item {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  width: 100%;
  padding: 0.375rem 0.625rem 0.375rem 0.375rem;
  font: inherit;
  font-size: var(--portal-text-13);
  color: var(--portal-ink);
  text-align: left;
  background: none;
  border: 0;
  border-radius: var(--portal-radius);
  cursor: pointer;
}
.portal-add-menu-item:hover,
.portal-add-menu-item:focus-visible { background: var(--crm-head); }
.portal-activity-filters { flex-wrap: wrap; margin: 0; padding: 0.625rem 0.75rem; border-bottom: 1px solid var(--crm-line); }
.portal-activity-filters a { font-size: var(--portal-text-12); }
/* The list scrolls on its own; the card's head and filters stay put above it. */
.portal-activities { display: flex; flex-direction: column; }
.portal-activity-list { flex: 1 1 auto; min-height: 0; max-height: 32rem; margin: 0; padding: 0; overflow-y: auto; overscroll-behavior: contain; list-style: none; }
.portal-activity { border-bottom: 1px solid var(--crm-line); }
/* A round mark per kind, coloured as the kind. */
.portal-activity-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: var(--portal-control-xs);
  color: var(--crm-quiet);
  background: var(--crm-head);
  border-radius: var(--portal-round);
}
.portal-activity:last-child { border-bottom: 0; }
.portal-activity .portal-activity-kind { font-size: var(--portal-text-12); font-weight: 600; color: var(--crm-label); white-space: nowrap; }
.portal-activity.is-stage .portal-activity-kind,
.portal-activity.is-stage .portal-activity-icon { color: var(--crm-teal); }
.portal-activity.is-stage .portal-activity-icon { background: var(--portal-teal-wash); }
.portal-activity.is-move-back .portal-activity-kind,
.portal-activity.is-move-back .portal-activity-icon { color: var(--crm-amber); }
.portal-activity.is-move-back .portal-activity-icon { background: var(--crm-amber-wash); }
/* A Lead claimed back from a Partner (crm slice 25): a change of hands, marked like a move back. */
.portal-activity.is-claim .portal-activity-kind,
.portal-activity.is-claim .portal-activity-icon { color: var(--crm-amber); }
.portal-activity.is-claim .portal-activity-icon { background: var(--crm-amber-wash); }
.portal-activity.is-call .portal-activity-icon,
.portal-add-menu-item.is-call .portal-activity-icon { color: var(--portal-blue); background: var(--portal-blue-wash); }
.portal-activity.is-email .portal-activity-icon,
.portal-add-menu-item.is-email .portal-activity-icon { color: var(--portal-purple); background: var(--portal-purple-wash); }
.portal-activity.is-meeting .portal-activity-icon,
.portal-add-menu-item.is-meeting .portal-activity-icon { color: var(--portal-brown); background: var(--portal-brown-wash); }
.portal-activity.is-task .portal-activity-icon { color: var(--portal-positive); background: var(--portal-positive-wash); }

/* Two lines per To-do and per Activity -- what it is, who and when; then what it says,
   cut to the line -- and the whole of it opens its pop-up, which shows it all. */
.portal-row-open {
  display: grid;
  grid-template-columns: 1.75rem minmax(0, 1fr);
  gap: 0.125rem 0.75rem;
  align-items: center;
  width: 100%;
  padding: 0.625rem 1rem;
  font: inherit;
  font-size: var(--portal-text-13);
  color: var(--portal-ink);
  text-align: left;
  background: none;
  border: 0;
  cursor: pointer;
}
.portal-row-open:hover,
.portal-row-open:focus-visible { background: var(--crm-head); }
.portal-row-open > .portal-activity-icon { grid-row: span 2; align-self: start; }
.portal-row-head { display: flex; align-items: baseline; gap: 0.5rem; min-width: 0; }
.portal-row-head > * { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.portal-row-text { grid-column: 2; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.portal-row-text:empty { display: none; }
.portal-row-who { font-size: var(--portal-text-12); color: var(--crm-quiet); white-space: nowrap; }
.portal-row-at { flex: none; margin-left: auto; }

/* A small round button that is only its mark: + adds a To-do, the tick marks one done. */
.portal-icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: var(--portal-control-xs);
  padding: 0;
  color: var(--crm-quiet);
  background: none;
  border: 0;
  border-radius: var(--portal-round);
  cursor: pointer;
}
.portal-icon-button:hover,
.portal-icon-button:focus-visible { color: var(--crm-teal); background: var(--portal-teal-wash); }
.portal-to-do-tick:hover,
.portal-to-do-tick:focus-visible { color: var(--portal-positive); background: var(--portal-positive-wash); }

/* A To-do's or an Activity's pop-up: what it is, who and when, above its form. */
.portal-to-do-pop-up,
.portal-activity-pop-up { padding-top: 1.25rem; }
.portal-to-do-pop-up > .portal-pop-up-title,
.portal-to-do-pop-up > p,
.portal-activity-pop-up > .portal-pop-up-title,
.portal-activity-pop-up > p { margin-left: 1.5rem; margin-right: 1.5rem; }
.portal-to-do-pop-up > .portal-meta,
.portal-activity-pop-up > .portal-meta { margin-top: -0.5rem; margin-bottom: 0; font-size: var(--portal-text-12); }
.portal-crm .portal-to-do-pop-up .portal-form,
.portal-crm .portal-activity-pop-up .portal-form { padding-top: 1rem; }
.portal-pop-up-planned { margin-top: 0.75rem; margin-bottom: 0; font-size: var(--portal-text-13); color: var(--crm-teal); }
.portal-pop-up-body { margin-top: 0.75rem; font-size: var(--portal-text-13); overflow-wrap: anywhere; }
.portal-activity-pop-up > .portal-form-actions { margin: 1.25rem 0 0; }
.portal-crm .portal-to-do-done-form { padding-top: 1.25rem; }

/* On a wide screen the card stays in view under the title band and fills the window
   below it, its list scrolling inside. */
@media (min-width: 64rem) {
  .portal-activities {
    position: sticky;
    top: calc(var(--crm-header-height) + var(--crm-title-height) + var(--crm-gap));
    max-height: calc(100vh - var(--crm-header-height) - var(--crm-title-height) - 2 * var(--crm-gap));
  }
  .portal-activity-list { max-height: none; }
}

/* A details card edited in place (a Lead's Customer): the same rows
   in the same places, each editable value now a light box at the value's size, so the
   card reads the same and shows what can change. Save and Cancel take the pencil's place. */
.portal-card-edit-actions { display: flex; align-items: center; gap: 0.875rem; }
.portal-card-edit-actions .portal-quiet { font-size: var(--portal-text-12); font-weight: 500; letter-spacing: 0; text-transform: none; }
.portal-crm .portal-card-edit-actions .portal-button { height: var(--portal-control-xs); padding: 0 0.875rem; font-size: var(--portal-text-12); }
.portal-crm-card.is-editing .portal-facts dt label { font: inherit; color: inherit; cursor: pointer; }
.portal-crm-card.is-editing .portal-facts dd:has(.portal-fact-input) { padding-top: 0.25rem; padding-bottom: 0.25rem; }
.portal-fact-input input,
.portal-fact-input select,
.portal-fact-input textarea {
  display: block;
  width: 100%;
  min-height: 2rem;
  margin: 0;
  padding: 0.25rem 0.5rem;
  font: inherit;
  font-size: var(--portal-text-13);
  line-height: 1.5;
  color: var(--portal-ink);
  background: var(--portal-surface);
  border: 1px solid var(--portal-edge);
  border-radius: var(--portal-radius);
  resize: vertical;
}
.portal-fact-input input:hover,
.portal-fact-input select:hover,
.portal-fact-input textarea:hover { border-color: var(--portal-edge-hover); }
.portal-fact-input input:focus,
.portal-fact-input select:focus,
.portal-fact-input textarea:focus { outline: none; border-color: var(--portal-teal); box-shadow: var(--portal-focus-ring); }
.portal-fact-input.is-invalid input,
.portal-fact-input.is-invalid select,
.portal-fact-input.is-invalid textarea { border-color: var(--portal-danger); }
.portal-fact-input .errorlist { margin: 0.25rem 0 0; padding: 0; list-style: none; font-size: var(--portal-text-12); color: var(--portal-danger); }
.portal-crm-card.is-editing > form > .errorlist { margin: 0; padding: 0.625rem 1rem; list-style: none; font-size: var(--portal-text-13); color: var(--portal-danger); background: var(--portal-danger-wash); }

/* Days without contact, beside the Activities title: green inside its Stage's Contact
   window, red past it, grey when no window is set. */
.portal-activity-title { display: flex; align-items: center; gap: 0.625rem; flex-wrap: wrap; }
.portal-contact-quiet {
  padding: 0.125rem 0.5rem;
  font-size: var(--portal-text-11);
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--crm-quiet);
  background: var(--portal-badge);
  border-radius: var(--portal-pill);
  white-space: nowrap;
}
.portal-contact-quiet.is-safe { color: var(--portal-positive); background: var(--portal-positive-wash); }
.portal-contact-quiet.is-late { color: var(--portal-danger); background: var(--portal-danger-tint); }

/* The To-dos card, above the Activities: one line per open To-do, amber when due
   today, red when late, with its tick. A long list scrolls inside the card. */
.portal-to-dos { position: relative; }
.portal-to-do-list { margin: 0; padding: 0; list-style: none; max-height: 16rem; overflow-y: auto; }
.portal-to-do { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; padding-right: 0.5rem; }
.portal-to-do + .portal-to-do { border-top: 1px solid var(--crm-edge); }
.portal-to-do form { margin: 0; }
.portal-to-do-when { font-size: var(--portal-text-12); font-weight: 600; color: var(--crm-teal); white-space: nowrap; }
.portal-to-do .portal-activity-icon { color: var(--crm-teal); background: var(--portal-teal-wash); }
.portal-to-do.is-due { background: var(--portal-amber-faint); }
.portal-to-do.is-due .portal-to-do-when,
.portal-to-do.is-due .portal-activity-icon { color: var(--crm-amber); }
.portal-to-do.is-due .portal-activity-icon { background: var(--crm-amber-wash); }
.portal-to-do.is-late { background: var(--portal-danger-wash); }
.portal-to-do.is-late .portal-to-do-when,
.portal-to-do.is-late .portal-activity-icon { color: var(--portal-danger); }
.portal-to-do.is-late .portal-activity-icon { background: var(--portal-danger-tint); }
.portal-to-do .portal-row-open:hover { background: var(--portal-hover-faint); }
.portal-to-do-none { padding: 0.75rem 1rem; font-size: var(--portal-text-13); }
.portal-fact-input + .portal-fact-input { margin-top: 0.375rem; }
/* A pop-up's To-do sits apart from what was said: it is optional. */
.portal-pop-up .portal-field:has([name="to_do_kind"]) { margin-top: 1.25rem; padding-top: 1rem; border-top: 1px dashed var(--crm-edge); }

/* What a change said, as a banner over the top of the Activities list that fades after
   a few seconds; a refusal stays until the next page. */
.portal-activities { position: relative; }
.portal-activity-toasts {
  position: absolute;
  top: 3.25rem;
  left: 0.75rem;
  right: 0.75rem;
  z-index: 2;
  margin: 0;
  padding: 0;
  list-style: none;
  pointer-events: none;
}
.portal-activity-toasts li {
  margin-bottom: 0.375rem;
  padding: 0.625rem 0.875rem;
  font-size: var(--portal-text-13);
  font-weight: 500;
  color: var(--portal-surface);
  background: var(--crm-teal);
  border-radius: var(--portal-radius);
  box-shadow: var(--portal-shadow-lift);
  animation: portal-toast 4s ease forwards;
}
.portal-activity-toasts li.error { background: var(--portal-danger); animation: none; pointer-events: auto; }
@keyframes portal-toast {
  0% { opacity: 0; transform: translateY(-4px); }
  8%, 80% { opacity: 1; transform: none; }
  100% { opacity: 0; visibility: hidden; }
}

/* The Brief card: one standing text, edited in place. */
.portal-brief { margin: 0; padding: 0.875rem 1rem; font-size: var(--portal-text-13); line-height: 1.6; }
form.portal-brief { padding: 0.625rem 0.75rem; }

/* A Sales desk list on a wide screen (Leads, Queue, Scorecards): everything
   down to the table's column heads stays put -- the header, the title, the tabs, the
   search -- and only the rows scroll, inside `.portal-list-body`, under heads stuck to
   its top. The Queue's two tables scroll as one, each head sticking in turn.
   Narrower, the page scrolls as one. */
@media (min-width: 64rem) {
  body.portal-list-page { display: flex; flex-direction: column; height: 100vh; overflow: hidden; }
  body.portal-list-page > .portal-header { flex: none; }
  body.portal-list-page > .portal-footer { display: none; }
  body.portal-list-page > .portal-main {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    padding-bottom: 1.25rem;
  }
  body.portal-list-page > .portal-main > * { flex: none; }
  body.portal-list-page > .portal-main > .portal-list-body {
    flex: 0 1 auto;
    min-height: 0;
    margin-bottom: 0;
    overflow: auto;
    overscroll-behavior: contain;
  }
  body.portal-list-page .portal-list-table thead th { top: 0; }
}

/* A Lead's page on a wide screen: everything down to the Stage bar stays
   put, and each column scrolls on its own -- the cards on the left, the Activities
   list on the right. Narrower, the page scrolls as one. */
@media (min-width: 64rem) {
  body.portal-record-page { display: flex; flex-direction: column; height: 100vh; overflow: hidden; }
  body.portal-record-page > .portal-header { flex: none; }
  body.portal-record-page > .portal-footer { display: none; }
  body.portal-record-page > .portal-main {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    padding-bottom: 1.25rem;
  }
  body.portal-record-page .portal-crm-head,
  body.portal-record-page .portal-stage-bar { flex: none; }
  /* A long repeats notice scrolls inside itself, so it never squeezes the columns
     below to nothing and leaves the Projects card out of reach. */
  body.portal-record-page .portal-repeats { flex: none; max-height: 30vh; overflow-y: auto; }
  body.portal-record-page .portal-record-split { flex: 1 1 auto; min-height: 0; align-items: stretch; }
  body.portal-record-page .portal-record-split > div { min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
  body.portal-record-page .portal-record-split > div:first-child { padding-right: 0.25rem; }
  body.portal-record-page .portal-record-split > div:first-child > :last-child { margin-bottom: 0; }
  body.portal-record-page .portal-record-split > div:last-child { display: flex; flex-direction: column; overflow: hidden; }
  body.portal-record-page .portal-to-dos { flex: none; margin-bottom: 1.25rem; }
  body.portal-record-page .portal-activities { position: relative; top: auto; flex: 1 1 auto; max-height: none; min-height: 0; margin-bottom: 0; }
}

/* Orders: the Order card beside the Quote it follows, and Place order's two lanes. */
.portal-project-status--placed { color: var(--crm-teal); background: var(--portal-teal-wash); }
.portal-order-card .portal-order-place { align-self: flex-start; }
.portal-order-lanes { display: grid; grid-template-columns: minmax(0, 3fr) minmax(18rem, 2fr); gap: 1.5rem; align-items: start; }
.portal-order-lines { width: 100%; }
/* A short list inside a card: its heads never stick as a Sales desk list's do. */
.portal-crm .portal-order-lines thead th { position: static; }
.portal-order-lines .portal-order-quantity { text-align: right; white-space: nowrap; }
.portal-order-line--cabinet td { font-weight: 600; }
.portal-order-line--part td:first-child { padding-left: 1.5rem; }
.portal-order-form { max-width: none; }
@media (max-width: 900px) {
  .portal-order-lanes { grid-template-columns: minmax(0, 1fr); }
}
/* Orders: each line's Purchase price and the total, for the Partner manager (slice 04). */
.portal-order-lines .portal-order-amount { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.portal-order-lines .portal-order-total th { text-align: right; }
.portal-order-lines .portal-order-total th,
.portal-order-lines .portal-order-total td { font-weight: 600; border-top: 1px solid var(--portal-rule-strong); }
.portal-order-reveal { margin-top: 0.5rem; font-size: var(--portal-text-13); color: var(--portal-muted); }
.portal-order-reveal form { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.portal-order-reveal .portal-pop-up { color: var(--portal-ink); font-size: var(--portal-text-16); }
.portal-order-lines-scroll { overflow-x: auto; }
.portal-order-lines td:first-child { white-space: nowrap; }
.portal-order-card .portal-order-lines { font-size: var(--portal-text-13); }
.portal-order-card .portal-order-lines th,
.portal-order-card .portal-order-lines td { padding-left: 0.5rem; padding-right: 0.5rem; }
.portal-order-card .portal-order-lines thead th { white-space: normal; letter-spacing: 0.02em; }
/* The Order card's state, deliveries and invoices, read from Odoo (orders slice 05). */
.portal-project-status--paid { color: var(--portal-surface); background: var(--crm-teal); }
.portal-project-status--delivered { color: var(--portal-surface); background: var(--portal-ink); }
.portal-project-status--cancelled { color: var(--portal-danger); background: var(--portal-danger-wash); }
.portal-order-unread { margin: 0.25rem 0 0; font-size: var(--portal-text-13); color: var(--portal-danger); }
.portal-order-deliveries { margin: 0; padding: 0; list-style: none; font-size: var(--portal-text-13); color: var(--portal-muted); }
.portal-order-deliveries li + li { margin-top: 0.125rem; }
.portal-order-delivery-name { margin-right: 0.375rem; color: var(--portal-ink); font-weight: 600; }
.portal-order-subhead { margin: 0.5rem 0 0.25rem; font-size: var(--portal-text-13); font-weight: 600; }
.portal-order-lines .portal-order-day { white-space: nowrap; }
/* A revision waiting to be sent onto the Order (orders slice 09). */
.portal-order-revision { display: flex; flex-direction: column; gap: 0.375rem; padding: 0.5rem 0.75rem; border-left: 3px solid var(--portal-ink); background: var(--portal-panel); }
.portal-order-revision-note { margin: 0; font-size: var(--portal-text-14); }
.portal-order-revision .portal-order-lock { margin: 0; }
.portal-order-card .portal-order-revise { align-self: flex-start; }
.portal-order-cancel, .portal-order-waive { display: flex; }
