:root {

    --brand-900: #1b1e21;
    --brand-800: #313131;
    --brand-700: #454749;
    --accent: #b45309;
    --accent-ink: #ffffff;
    --accent-50: #fdf5ec;

    --n-0: #ffffff;
    --n-25: #fbfcfd;
    --n-50: #f5f6f8;
    --n-100: #eef0f3;
    --n-200: #e2e5ea;
    --n-300: #cfd4db;
    --n-400: #9aa3ae;
    --n-500: #6b7480;
    --n-600: #4d555f;
    --n-700: #343a42;
    --n-900: #14171a;

    --green: #067647;  --green-bg: #ecfdf3;  --green-line: #abefc6;
    --amber: #b54708;  --amber-bg: #fffaeb;  --amber-line: #fedf89;
    --red:   #b42318;  --red-bg:   #fef3f2;  --red-line:   #fecdc9;
    --blue:  #175cd3;  --blue-bg:  #eff8ff;  --blue-line:  #b2ddff;

    --bg: var(--n-50);
    --surface: var(--n-0);
    --line: var(--n-200);
    --text: var(--n-900);
    --muted: var(--n-500);
    --faint: var(--n-400);

    --r-sm: 6px;
    --r: 8px;
    --r-lg: 11px;
    --r-pill: 999px;

    --sh-xs: 0 1px 2px rgba(16, 24, 40, .05);
    --sh-sm: 0 1px 3px rgba(16, 24, 40, .08), 0 1px 2px rgba(16, 24, 40, .04);
    --sh-md: 0 4px 12px rgba(16, 24, 40, .08);

    --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

    --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
    --s5: 20px; --s6: 28px; --s7: 40px;

    --h-page: 22px;
    --h1: 21px; --h2: 17px; --h3: 15px;

    /* control metrics. Touch values here, mouse values in the pointer query below */
    --body-fs: 15px;
    --ctl-h: 46px; --ctl-h-sm: 38px; --ctl-h-xs: 30px;
    --ctl-px: 18px; --ctl-fs: 15px;
    --fld-h: 46px; --fld-py: 11px; --fld-px: 12px; --fld-fs: 16px;
    --lbl-fs: 12.5px;
    --cell-py: 11px; --cell-px: 14px; --cell-fs: 14.5px;
    --card-pad: 18px;
    --icon: 18px;
    --pill-fs: 11px;

    --shell: 720px;
    --page-mid: 1040px;
    --page-wide: 1240px;

    --gutter: clamp(16px, 2vw, 32px);

    --shell-pad: 16px;

    --chrome: var(--surface);

    --navh: 62px;
    --topnav: 54px;

    --rail: 236px;

    --rail-mini: 68px;

    --rail-now: 0px;
}

/* a mouse needs no 46px target, so every control tightens to CRM density */
@media (hover: hover) and (pointer: fine) {
    :root {
        --h-page: 18px;
        --h1: 17px; --h2: 14.5px; --h3: 13.5px;
        --body-fs: 13.5px;
        --ctl-h: 32px; --ctl-h-sm: 28px; --ctl-h-xs: 24px;
        --ctl-px: 12px; --ctl-fs: 13px;
        --fld-h: 32px; --fld-py: 5px; --fld-px: 9px; --fld-fs: 13.5px;
        --lbl-fs: 12px;
        --cell-py: 6px; --cell-px: 10px; --cell-fs: 13px;
        --card-pad: 14px;
        --icon: 16px;
        --pill-fs: 10.5px;
        --topnav: 46px;
        --rail: 214px;
        --r-sm: 5px;
        --r: 7px;
        --r-lg: 9px;
    }
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    font-family: var(--font);
    font-size: var(--body-fs);
    line-height: 1.5;
    color: var(--text);
    background: var(--bg);
    -webkit-font-smoothing: antialiased;
    padding-bottom: calc(var(--navh) + env(safe-area-inset-bottom));
}

h1, h2, h3 { margin: 0; font-weight: 640; letter-spacing: -.018em; line-height: 1.25; }
h1 { font-size: var(--h1); }
h2 { font-size: var(--h2); }
h3 { font-size: var(--h3); }
p { margin: 0; }
a { color: var(--blue); text-decoration: none; }
button { font-family: inherit; }

body, .card { overflow-wrap: break-word; }

:focus-visible {
    outline: 3px solid var(--blue);
    outline-offset: 2px;
    border-radius: 4px;
}

.skip {
    position: absolute; left: 8px; top: -60px; z-index: 100;
    padding: 10px 14px; border-radius: var(--r-sm);
    background: var(--brand-900); color: #fff; font-weight: 620; font-size: 14px;
    transition: top .1s;
}
.skip:focus { top: 8px; }

.sl, .nav__item { overflow-wrap: normal; word-break: normal; }

.shell {
  max-width: var(--shell); margin: 0 auto;
  padding: var(--s5) var(--shell-pad) var(--s7);
}

.shell > *:first-child { margin-top: 0; }

.bar {
  position: sticky; top: 0;

  z-index: 70;
  background: var(--chrome);
  border-bottom: 1px solid var(--line);
}

.bar__in {
  max-width: var(--shell); margin: 0 auto;
  min-height: calc(var(--ctl-h) + 8px);

  padding: 8px 16px 12px;
  display: flex; align-items: center; gap: 10px;
}

.bar__title {
  font-size: var(--h-page); font-weight: 700; letter-spacing: -.022em;
  line-height: 1.2; margin: 0;
}

.nav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  background: var(--chrome);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom);
}

.nav__in { max-width: var(--shell); margin: 0 auto; display: flex; }

.nav__item {
  flex: 1; height: var(--navh);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  color: var(--faint); font-size: 10.5px; font-weight: 560; letter-spacing: .01em;
  text-decoration: none; position: relative;
}

.nav__item--on { color: var(--brand-900); }

.nav__item--on::before {
  content: ""; position: absolute; top: 0; left: 50%; transform: translateX(-50%);
  width: 26px; height: 2px; background: var(--brand-900); border-radius: 0 0 2px 2px;
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

.nav__item { min-width: 44px; }

body            { --page: var(--shell); }

body.w-mid      { --page: var(--page-mid); }

body.w-wide     { --page: var(--page-wide); }

.shell, .bar__in, .nav__in { max-width: var(--page); }

.nav__head { display: contents; }

.nav__brand { display: none; }

.nav__toggle { display: none; }

.nav__foot { display: none; }

@media (min-width: 900px) {
  :root { --navh: 0px; --shell-pad: var(--gutter); --gutter: clamp(14px, 1.4vw, 24px); }
  .shell     { max-width: none; padding: var(--s5) var(--shell-pad) var(--s7); }
  .bar__in   { max-width: none; }
  .nav__in   { max-width: none; }
  .nav {
      position: sticky; top: 0; bottom: auto; left: auto; right: auto;
      border-top: 0; border-bottom: 1px solid var(--line);
      padding-bottom: 0; z-index: 70;
      box-shadow: var(--sh-xs);
    }
  .nav__in { align-items: center; gap: 2px; padding: 0 var(--gutter); }
  .nav__brand {
      display: inline-flex; align-items: center; height: var(--topnav);
      margin-right: var(--s5);
      font-size: 16px; font-weight: 700; letter-spacing: -.03em; color: var(--brand-900);
    }
  .nav__item {
      flex: 0 0 auto; flex-direction: row; height: var(--topnav);
      gap: 8px; padding: 0 13px; border-radius: var(--r-sm);
      font-size: 13.5px; font-weight: 580; letter-spacing: 0; color: var(--n-600);
    }
  .nav__item .i-lg { width: 17px; height: 17px; }
  .nav__item--on { color: var(--brand-900); }
  .nav__item--on::before {
      top: auto; bottom: 0; left: 13px; transform: none;
      width: calc(100% - 26px); height: 2px; border-radius: 2px 2px 0 0;
    }
  .bar {
      position: sticky; top: 0;
      background: var(--chrome);
      border-bottom: 1px solid var(--line);
    }
  .bar__in { min-height: calc(var(--ctl-h) + 4px); padding: var(--s2) var(--gutter); gap: var(--s3); align-items: center; }
  .bar__title { line-height: 1.15; }
  .crumb { margin-top: 1px; }
}

@media (min-width: 1024px) {
  :root { --rail-now: var(--rail); }
  :root.rail-mini { --rail-now: var(--rail-mini); }
  body { padding-left: var(--rail-now); transition: padding-left .16s ease; }
  .nav {
      position: fixed; top: 0; bottom: 0; left: 0; right: auto;
      /* above .bar (70): the edge handle protrudes past the rail and the bar would paint over it */
      width: var(--rail-now); z-index: 80;
      display: flex; flex-direction: column;
      background: var(--chrome); box-shadow: none;
      border-bottom: 0; border-right: 1px solid var(--line);
      backdrop-filter: none; -webkit-backdrop-filter: none;
      transition: width .16s ease;
    }
  .nav__in {
      position: relative;
      flex-direction: column; align-items: stretch; gap: 2px;
      width: 100%; max-width: none; height: 100%;
      padding: var(--s4) var(--s3) 12px;
    }
  .nav__head {
      display: flex; align-items: center; gap: var(--s1);
      margin: 0 0 var(--s3);
    }
  .nav__brand {
      flex: 1; min-width: 0;
      height: var(--ctl-h); padding: 0 11px; margin: 0;
      font-size: 15.5px;
    }
  /* the handle straddles the rail's edge, so it reads as the thing that moves the edge */
  .js .nav__toggle {
      position: absolute; top: 20px; right: 0; z-index: 2;
      transform: translateX(50%);
      display: flex; align-items: center; justify-content: center;
      width: 22px; height: 22px; flex: none; padding: 0;
      border: 1px solid var(--n-300); border-radius: var(--r-pill);
      background: var(--surface); color: var(--muted); cursor: pointer;
      box-shadow: var(--sh-xs);
      transition: background .14s ease, color .14s ease, border-color .14s ease;
    }
  /* 22px to look at, 40px to hit */
  .js .nav__toggle::after {
      content: ""; position: absolute; inset: -9px; border-radius: var(--r-pill);
    }
  .nav__toggle .i {
      width: 13px; height: 13px;
      transition: transform .18s ease;
    }
  .nav__toggle:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
  :root.rail-mini .nav__toggle .i { transform: rotate(180deg); }
  .nav__item {
      width: 100%; height: 38px; justify-content: flex-start;
      padding: 0 11px; font-size: 13.5px; gap: 10px;
      white-space: nowrap;
    }
  .nav__item--on { background: var(--n-100); }
  .nav__item--on::before {
      top: 8px; bottom: 8px; left: 0; right: auto;
      width: 3px; height: auto; border-radius: 0 3px 3px 0;
    }
  :root.rail-mini .nav__head { justify-content: center; }
  :root.rail-mini .nav__brand {
      flex: none; width: 100%; height: 30px; padding: 0; justify-content: center;
    }
  :root.rail-mini .nav__item { justify-content: center; padding: 0; gap: 0; }
  :root.rail-mini .nav__t,
    :root.rail-mini .nav__brand-t {
      position: absolute; width: 1px; height: 1px; margin: -1px;
      overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
    }
  .nav__foot {
      display: block; margin: auto 0 0;
      padding-top: 10px; border-top: 1px solid var(--line);
    }
  .nav__item--out {
      width: 100%; background: none; border: 0; cursor: pointer;
      font-family: inherit; font-size: inherit; text-align: left;
      color: var(--red);
    }
}

@media (min-width: 1024px) and (hover: hover) {
  .nav__toggle:hover { border-color: var(--n-400); background: var(--n-50); color: var(--text); }
}

@media (prefers-reduced-motion: reduce) {
  .nav__toggle, .nav__toggle .i { transition: none; }
}

@media (hover: hover) {
  .nav__item:hover { color: var(--n-900); }
  .nav__item:hover .i { opacity: .9; }
}

@media (hover: hover) and (pointer: fine) {
  .nav__item, .seg, .qa__b, .pager__b { cursor: pointer; }
}

.shell > section + section,
.shell > .cards + .cards { margin-top: var(--s6); }

.shell > h2, .shell > .sl { margin-top: var(--s6); margin-bottom: var(--s3); }

.shell > h2:first-child, .shell > .sl:first-child { margin-top: 0; }

.shell > .toast { margin-bottom: var(--s5); }

.shell > .toast:first-child { margin-top: 0; }

@media (max-width: 900px) {
  .shell { padding-bottom: calc(var(--s7) + 62px); }
}

@media (max-width: 760px) {
  :root { --shell-pad: 8px; }
  .shell > *,
    .card, .cards, .doors, .door,
    .cal, .cal__grid, .cal__body, .cal__head,
    .cal--week, .cal--day, .colday, .evc,
    .empty, .toast, .pager {
      width: 100%;
      max-width: 100%;
      box-sizing: border-box;
    }
  html, body { overflow-x: hidden; }
}

@media (max-width: 380px) {
  :root { --shell-pad: 6px; }
}

@media (min-width: 1280px) {
  :root.rail-mini .pro {
      display: block;
      column-count: 2; column-gap: var(--s6);
    }
}

.bar__txt { min-width: 0; }

.crumb { min-width: 0; margin-top: 4px; }

.crumb__l {
  display: flex; align-items: center; flex-wrap: nowrap;
  gap: 4px; margin: 0; padding: 0; list-style: none;
  overflow: hidden;
}

.crumb__i { display: inline-flex; align-items: center; gap: 4px; min-width: 0; }

.crumb__a {
  font-size: 12px; color: var(--muted); text-decoration: none;
  white-space: nowrap;
}

@media (hover: hover) {
  .crumb__a:hover { color: var(--text); text-decoration: underline; }
}

.crumb__a:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; border-radius: 3px; }

.crumb__now {
  font-size: 12px; color: var(--faint); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}

.crumb__s { width: 11px; height: 11px; color: var(--n-300); flex: none; }

@media (max-width: 700px) {
  .crumb { display: none; }
}

.backlink {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: var(--ctl-h-xs); padding: 0 10px 0 7px;
  margin-bottom: var(--s3);
  border: 1px solid var(--line); border-radius: var(--r-pill);
  background: var(--surface); color: var(--n-700);
  font-size: var(--ctl-fs); font-weight: 580; text-decoration: none;
}

@media (hover: hover) {
  .backlink:hover { background: var(--n-50); border-color: var(--n-400); color: var(--text); }
}

.backlink:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }

.acct { position: relative; flex: none; margin-left: auto; display: block; }

.acct > summary { list-style: none; cursor: pointer; }

.acct > summary::-webkit-details-marker { display: none; }

.acct > summary::marker { content: ""; }

.acct__btn {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 8px; border-radius: var(--r-sm);
  color: inherit; text-decoration: none;
}

.acct__av {
  width: 30px; height: 30px; flex: none; border-radius: var(--r-pill);
  background: var(--brand-900); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 12.5px; font-weight: 700;
}

.acct__who { min-width: 0; display: flex; flex-direction: column; }

.acct__n { font-size: 13px; font-weight: 620; white-space: nowrap; }

.acct__c { font-size: 11.5px; color: var(--faint); }

.acct__caret { color: var(--faint); flex: none; transition: transform .14s ease; }

@media (hover: hover) {
  .acct > summary:hover .acct__btn { background: var(--n-50); }
}

.acct > summary:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; border-radius: var(--r-sm); }

.acct__menu {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 80;
  min-width: 210px; padding: 6px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r); box-shadow: 0 10px 30px rgba(0,0,0,.13);
}

.acct[open] .acct__caret { transform: rotate(180deg); }

.acct__item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 8px 11px; border-radius: var(--r-sm);
  font-size: 13px; font-weight: 560; text-align: left;
  color: var(--n-700); text-decoration: none;
  background: none; border: 0; cursor: pointer; font-family: inherit;
}

@media (hover: hover) {
  .acct__item:hover { background: var(--n-50); }
}

.acct__item:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; }

.acct__item--out { color: var(--red); }

.acct__menu form { margin: 0; }

@media (prefers-reduced-motion: reduce) {
  .acct__caret { transition: none; }
}

.modal {
  width: min(420px, calc(100vw - 32px));
  padding: 0;
  border: 1px solid var(--n-300);
  border-radius: var(--r-lg);
  background: var(--surface); color: var(--text);
  box-shadow: 0 24px 60px rgba(0,0,0,.22);
}

/* margin:auto — a deeply nested dialog was landing near the top; :modal scopes this to showModal() */
.modal:modal {
  margin: auto;
  max-height: calc(100vh - 48px);

  /* dvh so a phone's collapsing address bar does not push the footer off the screen */
  max-height: calc(100dvh - 48px);

  /* The dialog itself never scrolls. Its head and its actions stay put and the body between them
     takes the overflow, so a long list can never carry the heading away or hide the way out. */
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* Two shapes are in use: the blocks sitting directly inside the dialog, and the blocks wrapped in
   a form that posts them. The form has to carry the column as well, or it becomes the single flex
   item and the body inside it never becomes the part that scrolls. */
.modal:modal > form { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }

/* Optional: a head outside the scrolling body. Dialogs that keep their heading inside .modal__b
   are unaffected, because a short one has nothing to scroll. */
/* Ruled off from the body, so the head and the actions read as the dialog's frame whether or not
   the body between them is long enough to scroll. Every dialog is built the same three blocks. */
.modal__hd {
  flex: none;
  padding: var(--s5) var(--s5) var(--s3);
  border-bottom: 1px solid var(--line);
}

/* min-height:0 or the flex item refuses to shrink below its content and the dialog grows instead. */
.modal__b { flex: 1 1 auto; min-height: 0; overflow: auto; overscroll-behavior: contain; }

.modal__hd + .modal__b { padding-top: var(--s4); }

/* For a dialog that holds a list rather than a question. The default is sized for a sentence and
   two buttons, which squeezes a table of label-and-value down to one word per line. */
.modal--wide { width: min(680px, calc(100vw - 32px)); }

.modal::backdrop { background: rgba(17, 20, 24, .45); }

.modal__b { padding: var(--s5) var(--s5) var(--s4); }

.modal__h { font-size: var(--h2); font-weight: 680; margin: 0; line-height: 1.35; }

.modal__m { font-size: var(--body-fs); color: var(--muted); margin: 8px 0 0; line-height: 1.5; }

.modal__f {
  flex: none;
  display: flex; gap: 10px; justify-content: flex-end;
  padding: var(--s4) var(--s5) var(--s5);
  border-top: 1px solid var(--line);
}

.modal__b[hidden] + .modal__f { border-top: 0; }

@media (max-width: 480px) {
  .modal__f { flex-direction: column-reverse; }
  .modal__f .btn { width: 100%; }
}

@media (max-width: 1099px) {
  .acct__who, .acct__caret { display: none; }
  .acct__btn { padding: 4px; gap: 0; }
  .acct__menu {
      min-width: 200px;
      max-width: calc(100vw - 16px);
    }
}

@media (max-width: 1099px) and (pointer: coarse) {
  .acct__item { padding: 14px; font-size: 15px; }
}

.authbody { padding: 0; }

.card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r);
    box-shadow: var(--sh-xs);
    padding: var(--card-pad);
}

.card + .card { margin-top: 8px; }

a.card { display: block; color: inherit; transition: box-shadow .13s, border-color .13s, transform .13s; }
a.card:active { transform: scale(.994); }
.card.narrow { max-width: 440px; margin-inline: auto; }

.pad { padding: 14px; }
.pad-sm { padding: 10px 14px; }
.hr { border-top: 1px solid var(--line); }

.card--flush { padding: 0; overflow: hidden; }

.sl {
    display: flex; align-items: center; justify-content: space-between; gap: var(--s3);
    font-size: 11px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
    color: var(--faint);
    margin: var(--s5) 0 7px;
}

.fld { margin-bottom: var(--s4); }

.lbl {
    display: block;
    font-size: var(--lbl-fs); font-weight: 600; color: var(--n-600);
    margin-bottom: 5px;
}

.hint { display: block; font-size: 12px; color: var(--faint); margin-top: 7px; }

/* The asterisk on the label of an answer that is owed, shared by every form in the app. Optional is
   said by its absence: a second badge beside every other field is noise, not information. */
.req { margin-left: 2px; color: var(--red); font-weight: 600; }

/* The record screen alone decides per line, so its markers start hidden and script shows the ones
   the chosen status owes. Everywhere else the field is either required or it is not. */
[data-rec-live] .req { display: none; }
[data-rec-live] .req[data-show] { display: inline; }

.inp, .ta, .sel {

    display: block;
    width: 100%;
    min-height: var(--fld-h);
    padding: var(--fld-py) var(--fld-px);
    border: 1px solid var(--n-300);
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--text);
    font-family: inherit;

    font-size: var(--fld-fs);
}

.ta { min-height: 92px; resize: vertical; line-height: 1.5; }

.inp::placeholder, .ta::placeholder { color: var(--n-400); opacity: 1; }

.inp:focus, .ta:focus, .sel:focus {
    outline: none;
    border-color: var(--blue);
    box-shadow: 0 0 0 3px var(--blue-bg);
}

.inp:disabled, .ta:disabled, .sel:disabled { background: var(--n-50); color: var(--faint); }

.inp[aria-invalid="true"], .ta[aria-invalid="true"], .sel[aria-invalid="true"] {
    border-color: var(--red);
}

.inp[aria-invalid="true"]:focus,
.ta[aria-invalid="true"]:focus,
.sel[aria-invalid="true"]:focus {
    border-color: var(--red);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--red) 18%, transparent);
}

.err,
.field-validation-error {
    display: block;
    color: var(--red);
    font-size: 12.5px;
    font-weight: 540;
    margin-top: 6px;
}

.field-validation-valid:empty, .err:empty { display: none; }

.pw { position: relative; display: block; }

.pw .inp { display: block; padding-right: calc(var(--fld-h) + 8px); }

.pw__t {
    position: absolute; right: 5px; top: 50%; transform: translateY(-50%);
    width: calc(var(--fld-h) - 8px); height: calc(var(--fld-h) - 8px);
    display: flex; align-items: center; justify-content: center;
    border: 0; border-radius: var(--r-sm); background: none;
    color: var(--faint); cursor: pointer;
}

@media (hover: hover) {
    .pw__t:hover { background: var(--n-100); color: var(--text); }
}

.pw__t:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; color: var(--text); }
.pw__t[aria-pressed="true"] { color: var(--brand-900); }

.pw__t { display: none; }
.js .pw__t { display: flex; }

[hidden] { display: none !important; }

.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;

    min-height: var(--ctl-h);
    padding: 0 var(--ctl-px);
    border-radius: var(--r-sm);
    border: 1px solid transparent;
    font-size: var(--ctl-fs); font-weight: 600;
    cursor: pointer; text-decoration: none;
    transition: filter .12s, background .12s;
}

.btn:active { filter: brightness(.93); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }

.btn--full { width: 100%; }
.btn--pri { background: var(--brand-900); color: #fff; }
.btn--sec { background: var(--surface); color: var(--n-700); border-color: var(--n-300); }
.btn--danger { background: var(--red); color: #fff; }

/* Quiet: bordered from the start so it is findable without a pointer, and held slightly back so a
   secondary action never competes with the primary one beside it. Hover brings it up to full
   rather than dimming it, which is the direction that reads as "this is live". */
.btn--ghost {
    background: none;
    color: var(--muted);
    border-color: var(--line);
    font-weight: 500;
    opacity: 0.8;
    transition: opacity .12s, filter .12s;
}

@media (hover: hover) and (pointer: fine) {
    .btn--ghost:hover { opacity: 1; color: var(--n-700); }
}

.btn--ghost:focus-visible { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
    .btn--ghost { transition: none; }
}

.btn--xs { min-height: var(--ctl-h-xs); padding: 0 10px; gap: 5px; font-size: calc(var(--ctl-fs) - 1px); }
.btn--sm { min-height: var(--ctl-h-sm); padding: 0 calc(var(--ctl-px) - 3px); font-size: calc(var(--ctl-fs) - .5px); }
.btn--md { min-height: var(--ctl-h); padding: 0 var(--ctl-px); font-size: var(--ctl-fs); }

.btn--link {
    background: none; border: 0; padding: 0;
    min-height: auto;
    color: var(--muted); font-size: 13px;
    text-decoration: underline; cursor: pointer;
}

.btn-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); }

/* A form's own actions sit against the trailing edge, where a form is finished. Row actions and
   page links keep the leading edge — those are read with the content, not pressed to commit it. */
.btn-row--end { justify-content: flex-end; }

/* The status and any action on it share the head's trailing edge. */
.jobhead__r { display: inline-flex; align-items: center; gap: var(--s2); margin-bottom: var(--s4); }

/* On a phone a commit button is a target, not a label: full width and stacked. Reversed, so the
   primary — last in the row, and last in the DOM — comes out on top. */
@media (max-width: 560px) {
    .btn-row--end { flex-direction: column-reverse; align-items: stretch; }
    .btn-row--end .btn { width: 100%; }
}

/* Start and Finish share a row, the note runs under both. One shape wherever these three fields
   appear, so booking and rescheduling do not look like different forms. */
.book { display: grid; grid-template-columns: 1fr; gap: 0 var(--s4); }
@media (min-width: 700px) {
  .book { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .book .fld--all { grid-column: 1 / -1; }
}

.toast {
    display: flex; gap: 10px; align-items: flex-start;
    padding: 10px 12px;
    border: 1px solid; border-radius: var(--r);
    font-size: 13px;
    margin: var(--s3) 0;
}

.toast__t { font-weight: 660; }
.toast__s { margin-top: 3px; }
.toast--ok { background: var(--green-bg); border-color: var(--green-line); color: #054f31; }
.toast--err { background: var(--red-bg); border-color: var(--red-line); color: #912018; }
.toast--warn { background: var(--amber-bg); border-color: var(--amber-line); color: #93370d; }
.toast--info { background: var(--blue-bg); border-color: var(--blue-line); color: #194185; }

.toast ul { margin: 5px 0 0; padding-left: 18px; }
.pad > .toast, .pad-sm > .toast { margin: 0; }
.toast li + li { margin-top: 3px; }


.pill {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 4px 7px;
    border-radius: var(--r-pill);
    border: 1px solid transparent;
    font-size: var(--pill-fs); font-weight: 640; white-space: nowrap;

    /* Declared, not inherited, so a pill is one height in a cell and in a button. A tight line box
       with even padding keeps the label and dot in the vertical middle rather than on the baseline. */
    line-height: 1;
}

.pill__d { width: 5px; height: 5px; border-radius: 50%; background: currentColor; flex: none; }

.pill--new  { background: var(--n-100);    color: var(--n-600); border-color: var(--n-200); }
.pill--info { background: var(--blue-bg);  color: var(--blue);  border-color: var(--blue-line); }
.pill--live { background: var(--amber-bg); color: var(--amber); border-color: var(--amber-line); }
.pill--done { background: var(--green-bg); color: var(--green); border-color: var(--green-line); }
.pill--warn { background: var(--red-bg);   color: var(--red);   border-color: var(--red-line); }
.pill--dead { background: var(--n-100);    color: var(--n-500); border-color: var(--n-300); }

/* The CRM's own order status (CrmStatusTagHelper). One line per status, so a colour is one edit. */
.crm-st--open       { background: var(--blue-bg);  color: var(--blue);  border-color: var(--blue-line); }
.crm-st--processing { background: #f4f3ff;         color: #5925dc;      border-color: #d9d6fe; }
.crm-st--hold       { background: var(--red-bg);   color: var(--red);   border-color: var(--red-line); }
.crm-st--cmr        { background: #fff4ed;         color: #c4320a;      border-color: #f9dbaf; }
.crm-st--pcmr       { background: #fdf2fa;         color: #c11574;      border-color: #fcceee; }
.crm-st--incomplete { background: #f0fdf9;         color: #107569;      border-color: #99f6e0; }
.crm-st--completed  { background: var(--green-bg); color: var(--green); border-color: var(--green-line); }
.crm-st--closed     { background: var(--n-100);    color: var(--n-600); border-color: var(--n-300); }
.crm-st--installed  { background: var(--blue-bg);  color: var(--blue);  border-color: var(--blue-line); }
.crm-st--pending    { background: var(--amber-bg); color: var(--amber); border-color: var(--amber-line); }
/* Service call (ServiceCallTagHelper): solid, so it never reads as the outlined CMR badge beside it. */
.svc { background: #c4320a; color: #fff; border-color: #c4320a; }
.svc .svc__i { width: 11px; height: 11px; flex: none; }

/* A CMR order carries the CMR badge's orange as an edge, so it stands out when scanning a list. */
tr.row--cmr > td:first-child { box-shadow: inset 3px 0 0 #c4320a; }

/* Badges that share a cell sit side by side and wrap rather than overflow a narrow column. */
.tags { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px; max-width: 100%; }

.crm-st--other      { background: var(--n-100);    color: var(--n-600); border-color: var(--n-200); }

table { width: 100%; border-collapse: collapse; }

th, td {
    text-align: left;
    padding: var(--cell-py) var(--cell-px);
    border-bottom: 1px solid var(--line);
    vertical-align: middle;
    font-size: var(--cell-fs);
}

thead th {
    font-size: calc(var(--cell-fs) - 2px); font-weight: 700;
    text-transform: uppercase; letter-spacing: .06em;
    color: var(--faint);
    background: var(--n-25);
    white-space: nowrap;
}

tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: var(--n-25); }

.num { font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; }

details > summary { cursor: pointer; }
details > summary:hover { background: var(--n-25); }

.money { font-variant-numeric: tabular-nums; }
.money--owed  { color: var(--red); }
.money--paid  { color: var(--green); }
.money--work  { color: var(--n-600); }
.money--muted { color: var(--muted); font-weight: 580; }
td.right, th.right { text-align: right; }

.rows > * + * { border-top: 1px solid var(--line); }

/* The side padding is the card's, not a table cell's: a row in a flush card sits beside plain
   cards on the same page, and 4px of difference reads as one of them being misaligned. */
.rw { display: flex; align-items: center; gap: 12px; padding: var(--cell-py) var(--card-pad); }
.rw__t { display: block; font-size: var(--cell-fs); font-weight: 600; }
.rw__s { font-size: max(12px, calc(var(--cell-fs) - 2px)); color: var(--muted); margin-top: 1px; }
.rw__r { text-align: right; white-space: nowrap; }

/* ---- Stats strip: the labelled figures across the top of a screen. ---- */
/* Shared, not module-owned: the dashboard, the job screens and the commissions screen all show one. */
/* Two up on a phone, one row from 700px. minmax(0, 1fr) so a long amount cannot widen a column. */
/* Separate bordered cards, not one divided strip: the dashboard's design, and the others follow it. */
/* Not in dashboard.css: only the dashboard loads that file, so elsewhere this padding was nothing. */
:root { --tile-py: 11px; --tile-px: 12px; }

@media (hover: hover) and (pointer: fine) {
    :root { --tile-py: 8px; --tile-px: 10px; }
}

.stats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s2); }

.stats__c {
    display: block;
    min-width: 0;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r);
    padding: var(--tile-py) var(--tile-px);
    color: inherit;
    text-decoration: none;

    /* stated, not inherited: the figures line up with the tables, whatever the strip is dropped into */
    text-align: left;
}

.stats__k {
    display: flex; align-items: center; gap: 5px;
    font-size: 10.5px; font-weight: 700; letter-spacing: .045em;
    text-transform: uppercase; color: var(--faint);
}

/* the figure is the point of the strip, so it gives up far less height than the label above it */
.stats__v {
    display: block;
    font-size: var(--h1); font-weight: 700; margin-top: 3px; letter-spacing: -.03em;
}

/* the accent marks a figure someone is waiting on, never one that is merely large */
.stats__v--act { color: var(--accent); }

.stats__s {
    display: block;
    font-size: max(11.5px, calc(var(--cell-fs) - 3px)); color: var(--faint); margin-top: 2px;
}

a.stats__c { transition: background .13s; }
a.stats__c:active { background: var(--n-50); }

/* the ring sits inside the cell: at the global 2px offset the card's own overflow clips it */
a.stats__c:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; border-radius: 0; }

@media (hover: hover) {
  a.stats__c:hover { background: var(--n-25); }
}

@media (prefers-reduced-motion: reduce) {
  a.stats__c { transition: none; }
}

/* One row from here: four figures is the common case, and each tile's own border needs no dividers. */
@media (min-width: 700px) {
  .stats { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); }
}

.empty { text-align: center; padding: var(--s6) var(--s5); }

.empty__i {
    width: 46px; height: 46px; margin: 0 auto var(--s3);
    border-radius: 50%;
    background: var(--n-100); color: var(--faint);
    display: flex; align-items: center; justify-content: center;
}

.empty__t { font-size: var(--cell-fs); font-weight: 600; }
.empty__s { font-size: 13px; color: var(--muted); margin-top: 4px; }

.empty__a { margin-top: var(--s4); display: flex; justify-content: center; gap: var(--s2); flex-wrap: wrap; }

.sprite { display: none; }

.i {
    width: var(--icon); height: var(--icon); flex: none;
    stroke: currentColor; fill: none;
    stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.i-sm { width: calc(var(--icon) - 4px); height: calc(var(--icon) - 4px); }

/* A spinner that takes an icon's place, so a button does not change size while it works. Sized
   off the same token as .i, and drawn rather than fetched: one more request while waiting on a
   request is the wrong thing to be doing. */
.spin {
    width: var(--icon); height: var(--icon); flex: none;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: spin 0.6s linear infinite;
}

.spin--sm { width: calc(var(--icon) - 4px); height: calc(var(--icon) - 4px); border-width: 1.8px; }

@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
    /* Still says "working" without the motion: a steady ring, no spin. */
    .spin { animation: none; border-right-color: currentColor; opacity: 0.5; }
}
.i-lg { width: calc(var(--icon) + 4px); height: calc(var(--icon) + 4px); }

.muted { color: var(--muted); font-size: 13.5px; }
.faint { color: var(--faint); }
.t-sm { font-size: 13px; }
.strong { font-weight: 640; }
.row { display: flex; align-items: center; gap: var(--s2); }
.between { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s3); }
.grow { min-width: 0; flex: 1; }
.none { flex: none; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* a wide table scrolls inside its own box; without this it is clipped by .card--flush */
.scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100%; }
.break { word-break: break-all; }
.center { text-align: center; }

.mt-1 { margin-top: var(--s1); }
.mt-2 { margin-top: var(--s2); }
.mt-3 { margin-top: var(--s3); }
.mt-4 { margin-top: var(--s4); }

/* List chrome shared by the jobs and installer lists, so the two cannot drift apart */
/* scrolls sideways rather than wrapping: a wrapped filter row changes the page height */
.segs {
  display: flex; gap: 4px; margin: var(--s4) 0 var(--s3);
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}

.segs::-webkit-scrollbar { display: none; }

.seg {
  flex: none; min-height: 36px; padding: 5px 12px; border-radius: var(--r-pill);
  background: var(--surface); border: 1px solid var(--line);
  color: var(--n-600); font-size: 12.5px; font-weight: 560;
  text-decoration: none; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 6px;
}

.seg--on { background: var(--brand-900); border-color: var(--brand-900); color: #fff; }


@media (hover: hover) {
  .seg:hover { border-color: var(--n-300); }

  /* the selected chip keeps its own edge; the grey border above reads as a gap on dark */
  .seg--on:hover { background: var(--brand-800); border-color: var(--brand-800); color: #fff; }
}

/* 44px is for thumbs; with a mouse the row can be compact */
@media (hover: hover) and (pointer: fine) {
  .seg { cursor: pointer; min-height: 26px; padding: 3px 10px; font-size: 12px; }
}

/* the selected chip is easy to miss, so the filter is also stated in words */
.resbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s3); flex-wrap: wrap;
  margin: var(--s5) 0 var(--s4);
  font-size: 13px; color: var(--muted);
}

.resbar__n { font-weight: 640; color: var(--text); }

/* ---- Search. Copied from the prototype. ---- */

.search { position: relative; margin-top: 16px; }

.search__i {
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
  color: var(--faint); pointer-events: none;
}

.search__in {
  width: 100%; min-height: var(--fld-h); padding: var(--fld-py) 38px var(--fld-py) 34px;
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); color: var(--text);
  font-family: inherit; font-size: var(--fld-fs);
  -webkit-appearance: none; appearance: none;
}

.search__in::-webkit-search-cancel-button { -webkit-appearance: none; }

.search__in:focus { outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px var(--blue-bg); }

.search__in::placeholder { color: var(--faint); }


.toolbar { display: block; }

.toolbar .search { margin-top: var(--s4); }

@media (min-width: 900px) {
  .search { max-width: 420px; }
  .toolbar {
    display: flex; align-items: center; gap: var(--s4);
    flex-wrap: wrap; margin-top: var(--s4);
  }
  .toolbar .search { flex: 0 1 380px; margin-top: 0; }
  .toolbar .segs { flex: 1 1 auto; justify-content: flex-end; margin: 0; }
}

/* ---- Pager. Copied from the prototype. ---- */

.pager {
  display: flex; align-items: center; justify-content: center; gap: 4px;
  flex-wrap: nowrap; margin-top: 18px;
} 

.pager__b {
  min-width: var(--ctl-h-sm); height: var(--ctl-h-sm); padding: 0 7px; margin: 4px 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface); color: var(--n-700);
  font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums;
  text-decoration: none; position: relative;
} 

.pager__b::after {
  content: ""; position: absolute; inset: -5px 0;   /* 34 + 10 = 44px tall target */
} 

@media (max-width: 760px) {
  .pager { gap: 8px; }
  .pager__b::after { inset: -5px; }
}

 

@media (max-width: 620px) {
}

/* the page you are on: a filled chip, and it stays filled on hover */
.pager__b--on,
.pager__b--on:hover {
  background: var(--brand-900);
  border-color: var(--brand-900);
  color: #fff;
  cursor: default;
} 

.pager__b--off { opacity: .35; pointer-events: none; } 

.pager__gap { color: var(--faint); padding: 0 2px; font-size: 13px; } 

.pager__count { text-align: center; font-size: 12px; color: var(--faint); margin-top: 10px; } 

@media (hover: hover) {
  .pager__b:hover { border-color: var(--n-300); background: var(--n-25); color: var(--text); }

  /* repaints its own fill: the plain :hover above would leave a white number on near-white */
  .pager__b--on:hover { background: var(--brand-800); border-color: var(--brand-800); color: #fff; }
}

@media (hover: hover) and (pointer: fine) {
  .nav__item, .seg, .pager__b { cursor: pointer; }
}

/* one dialog collects the value, so icon actions need no text box per row */
.modal__in { margin-top: var(--s4); text-align: left; }
.modal__in .lbl { display: block; margin-bottom: 6px; }
.modal__in .inp { width: 100%; }

/* app.js marks the document, so the no-script fallbacks disappear for everyone else */
.js .nojs { display: none; }

/* ---- Sort control ---- */

/* The filter panel: one bordered block holding search, filter and sort, as the CRM groups them. */
.filters { padding: var(--s4) var(--card-pad); margin-bottom: var(--s3); }

/* Fields share the width and wrap when one no longer fits, so no breakpoint has to count them. */
.filters__f {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
    gap: var(--s3);
    align-items: start;
}

/* start, not end: a field carrying a validation message is taller, and aligning bottoms would lift its input off the row. */
.filters__fl { min-width: 0; }

.filters__lb {
    display: block;
    margin-bottom: 5px;
    font-size: 12px;
    font-weight: 600;
    color: var(--muted);
}

/* One height token for every control, or an even grid still reads as ragged. */
.filters .search__in,
.filters .sortbar__sel {
    width: 100%;
    min-height: var(--ctl-h);
    padding-top: var(--fld-py);
    padding-bottom: var(--fld-py);
}

/* A date box is another control in the same grid, so it takes the same height and the same full width. */
/* Safari sizes one to its own idea of the text and ignores min-height, so appearance is reset and the height stated. */
.filters input[type="date"] {
    display: block;
    width: 100%;
    height: var(--ctl-h);
    min-height: var(--ctl-h);
    padding: var(--fld-py) var(--fld-px);
    font-family: inherit;
    font-size: var(--fld-fs);
    -webkit-appearance: none;
    appearance: none;
}

/* iOS centres the value inside the box it chose; left-aligned it lines up with the fields beside it. */
.filters input[type="date"]::-webkit-date-and-time-value { text-align: left; }

/* A tick is another control in the same grid, so its label takes the field height and sits on the row. */
.filters .pick-all { min-height: var(--ctl-h); }

/* Their own row across the full grid, sized to their labels rather than to a field. */
.filters__act {
    grid-column: 1 / -1;
    display: flex;
    justify-content: flex-end;
    gap: var(--s2);
}

/* The export acts on everything the filters match, so it sits above the table as a small row. */

/* The magnifier centres on this box, not on the field group that also holds the label. */
.search__f { position: relative; }


.sortbar__sel {
  width: auto; min-height: var(--ctl-h-sm); padding: var(--fld-py) var(--fld-px);
  font-size: var(--fld-fs); border-radius: var(--r-sm);
}

/* Phone: .tcards + .scroll-x--cards + .tcards-box; headers come from data-label because style-src 'self' drops inline styles */
@media (max-width: 760px) {
  .scroll-x--cards { overflow: visible; }

  /* the rows are cards now, so the wrapper drops its own border and background */
  .tcards-box {
      background: none;
      border: 0;
      box-shadow: none;
      overflow: visible;
      padding: 0 4px;
  }

  .tcards,
  .tcards tbody,
  .tcards tr,
  .tcards td { display: block; width: 100%; }

  .tcards thead { display: none; }

  .tcards tr {
      border: 1px solid var(--line);
      border-radius: var(--r);
      background: var(--surface);
      margin-bottom: var(--s2);
      padding: 2px 0 0;
  }

  .tcards tr:last-child { margin-bottom: 0; }

  /* On a phone the row is a card, so the orange edge moves from the first cell to the card itself. */
  .tcards tr.row--cmr { border-left: 3px solid #c4320a; }
  .tcards tr.row--cmr > td:first-child { box-shadow: none; }
  .tcards tr:hover { background: var(--surface); }

  .tcards td {
      display: flex;
      flex-wrap: wrap;
      align-items: baseline;
      gap: 4px var(--s3);
      padding: 6px 12px;
      border-bottom: 0;
      overflow-wrap: anywhere;
  }

  .tcards td::before {
      content: attr(data-label);
      flex: none;
      width: 86px;
      font-size: 10.5px; font-weight: 700;
      text-transform: uppercase; letter-spacing: .06em;
      color: var(--faint);

      /* The label heads a column of labels and lines up with them, not with the figure beside it. */
      text-align: left;

      /* A label longer than its box used to overrun the value beside it: "TOTAL (INC GST)$526.35". */
      overflow-wrap: anywhere;
  }

  /* the lead cell heads the card, so it reads as a title rather than another labelled field */
  .tcards td.tcards__lead {
      padding: 10px 12px 2px;
      font-size: 15.5px;
  }

  .tcards td.tcards__sub {
      padding-bottom: 8px;
      border-bottom: 1px solid var(--n-100);
  }

  .tcards td.tcards__lead::before,
  .tcards td.tcards__sub::before,
  .tcards td.tcards__act::before { display: none; }

  .tcards td.tcards__act {
      margin-top: 2px;
      padding: 10px 12px 12px;
      border-top: 1px solid var(--n-100);
  }

  .tcards td.tcards__act .tbl-act,
  .tcards td.tcards__act .btn-row { justify-content: flex-start; }
}

/* label via title + aria-label: a CSS tooltip would be clipped by the .scroll-x container */
.ibtn {
    width: var(--ctl-h-sm); height: var(--ctl-h-sm); flex: none; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid var(--n-300); border-radius: var(--r-sm);
    background: var(--surface); color: var(--n-700);
    cursor: pointer;
}

.ibtn--danger { border-color: var(--red-line); background: var(--red-bg); color: var(--red); }

.ibtn--go { border-color: var(--brand-900); background: var(--brand-900); color: #fff; }

.ibtn:active { filter: brightness(.93); }

/* tight ring: at the global 3px/+2px these would collide across a var(--s2) gap */
.ibtn:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }

@media (hover: hover) {
    .ibtn:hover { border-color: var(--n-400); background: var(--n-50); }
    .ibtn--danger:hover { background: var(--red); color: #fff; border-color: var(--red); }
    /* filled buttons repaint here, or the plain :hover above leaves a white icon on near-white */
    .ibtn--go:hover { background: var(--brand-800); border-color: var(--brand-800); color: #fff; }
}

/* Row actions. Left-aligned like every other column, so the eye tracks one edge. */
.tbl-act {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s2);
    justify-content: flex-start;
}

.tbl-act form { margin: 0; display: flex; align-items: center; gap: var(--s2); }

/* ---- The mark. Filled, so it deliberately does not inherit the stroke-only .i rules. ---- */
.logo { width: 26px; height: 26px; flex: none; display: block; }
.logo__bg { fill: var(--brand-900); }
.logo__t {
    fill: #fff;
    font-family: inherit;
    font-size: 11px; font-weight: 750; letter-spacing: -.03em;
}
.auth__mark { display: flex; justify-content: center; margin-bottom: var(--s4); }
.auth__mark .logo { width: 52px; height: 52px; }

/* mark plus wordmark; the collapsed rail hides the words and centres the mark */
.nav__brand { gap: var(--s2); }
.nav__brand .logo { width: 28px; height: 28px; }

/* a compact icon button for dense surfaces like the calendar cards */
.ibtn--sm { width: var(--ctl-h-xs); height: var(--ctl-h-xs); }

/* ---- Phone navigation: a drawer for everything, a bottom bar for what a thumb needs ---- */

/* No .tabbar and no drawer without script: the nav stays the bottom bar it has always been,
   which is why every rule here is behind .js. Six tabs is the fallback, not the design. */
.tabbar { display: none; }

.burger { display: none; }

@media (max-width: 899px) {
    .js .burger {
        display: inline-flex; align-items: center; justify-content: center;
        width: var(--ctl-h-sm); height: var(--ctl-h-sm); flex: none;
        margin-right: var(--s2); padding: 0;
        border: 1px solid var(--n-300); border-radius: var(--r-sm);
        background: var(--surface); color: var(--n-700);
        cursor: pointer;
    }

    .js .burger:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }

    /* The sidebar, off-canvas. visibility keeps it out of the tab order while closed. */
    .js .nav {
        position: fixed; top: 0; bottom: 0; left: 0; right: auto;
        width: min(82vw, 300px); z-index: 90;
        border-top: 0; border-right: 1px solid var(--line);
        box-shadow: var(--sh-md);
        overflow-y: auto; overscroll-behavior: contain;
        visibility: hidden;
        transform: translateX(-100%);
        transition: transform .22s ease, visibility .22s;
    }

    .js .nav[data-open] { visibility: visible; transform: none; }

    .js .nav__in { flex-direction: column; align-items: stretch; padding: var(--s3) var(--s2) var(--s5); }

    .js .nav__head { display: flex; align-items: center; padding: var(--s2) var(--s3) var(--s4); }

    .js .nav__brand {
        display: inline-flex; align-items: center; gap: var(--s2);
        font-size: 16px; font-weight: 700; letter-spacing: -.03em; color: var(--brand-900);
    }

    /* the drawer is closed by the veil, Escape or the burger, so the rail's collapse has no job here */
    .js .nav__toggle { display: none; }

    /* A row, not a tile: the drawer is a list read down, not a bar scanned across. */
    .js .nav__item {
        flex: none; flex-direction: row; justify-content: flex-start;
        height: auto; min-height: 46px; gap: var(--s3); padding: 0 var(--s3);
        border-radius: var(--r-sm);
        font-size: 14px; font-weight: 580; letter-spacing: 0; color: var(--n-700);
    }

    .js .nav__item--on { color: var(--brand-900); background: var(--n-50); }

    /* the marker moves to the leading edge, where a list is read from */
    .js .nav__item--on::before {
        top: 8px; bottom: 8px; left: 0; transform: none;
        width: 3px; height: auto; border-radius: 0 2px 2px 0;
    }

    .js .nav__foot { display: block; margin-top: var(--s3); padding-top: var(--s3); border-top: 1px solid var(--n-100); }
    .js .nav__foot .nav__item { width: 100%; border: 0; background: none; font: inherit; cursor: pointer; }

    .js .veil {
        position: fixed; inset: 0; z-index: 85;
        background: rgba(0, 0, 0, .38);
    }

    .js .veil[hidden] { display: none; }

    /* The bottom bar. Same metrics the nav had, so nothing below it shifts. */
    .js .tabbar {
        position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
        display: flex;
        background: var(--chrome);
        border-top: 1px solid var(--line);
        padding-bottom: env(safe-area-inset-bottom);
    }

    .js .tabbar__i {
        flex: 1; min-width: 0; height: var(--navh);
        display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
        color: var(--faint); font-size: 10.5px; font-weight: 560; letter-spacing: .01em;
        text-decoration: none; position: relative;
    }

    /* five labels across a narrow phone: clip rather than wrap, or one long word doubles the bar */
    .js .tabbar__t { max-width: 100%; padding: 0 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

    .js .tabbar__i--on { color: var(--brand-900); }

    .js .tabbar__i--on::before {
        content: ""; position: absolute; top: 0; left: 50%; transform: translateX(-50%);
        width: 26px; height: 2px; background: var(--brand-900); border-radius: 0 0 2px 2px;
    }

    /* the drawer scrolls itself; the page behind it must not */
    .js body.drawer-open { overflow: hidden; }
}

@media (max-width: 899px) and (prefers-reduced-motion: reduce) {
    .js .nav { transition: none; }
}

/* ---- Print: the sheet, and nothing the screen wraps it in ---- */

/* The explanatory line a money screen carries above its figures. Shared: seven screens across
   two modules use it, and the per-module copies had drifted to different margins. */
.earn__note {
    display: flex; align-items: flex-start; gap: var(--s2);
    margin: var(--s4) 0;
    font-size: 13px; line-height: 1.45; color: var(--muted);
}

/* The glyph is optically taller than the first line, so it drops to the text's cap height. */
.earn__note > .i { margin-top: 1px; }

/* The head has already paid for the gap above it. */
.jobhead + .earn__note { margin-top: 0; }

/* The back link already carries the gap below it. */
.jobhead + .sl { margin-top: 0; }

/* Screen-only: the masthead exists for paper, where there is no app chrome to say what this is. */
.pmast { display: none; }

/* First thing in the sheet, under a head that has already paid for the gap: .sl's own top
   margin stacked on it and left a hand's width of nothing above the document. */
.sheet__h:first-child { margin-top: 0; }

@media print {
    /* Named by class, not by "everything that is not .shell": .js .tabbar carries two classes
       and beat that rule on specificity, which is how the tab bar reached the printed page. */
    .nav,
    .tabbar,
    .veil,
    .bar,
    .skip,
    .backlink,
    .jobhead,
    .btn-row,
    .toast,
    .filters,
    .resbar,
    .sheet__h,
    .pager { display: none !important; }

    .pmast {
        display: flex; align-items: center; gap: var(--s3);
        padding-bottom: var(--s3); margin-bottom: var(--s4);
        border-bottom: 1px solid var(--n-900);
        color: var(--n-900);
    }

    .pmast .logo { width: 34px; height: 34px; }

    /* The mark's brand colour does print, and halftones to a grey block on a mono printer. */
    .pmast .logo__bg { fill: var(--n-900); }
    .pmast .logo__t { fill: var(--n-0); }

    .pmast__brand { font-weight: 700; }

    .pmast__doc {
        font-size: 11px; font-weight: 700;
        letter-spacing: .07em; text-transform: uppercase;
    }

    /* Pushed to the far edge, so the mark and the date bracket the sheet. */
    .pmast__when { margin-left: auto; white-space: nowrap; font-size: 11px; }

    /* A card table prints as a table: the card layout is a narrow-screen affordance, and paper
       is always wide enough. Without this every row printed as a stack of labelled lines. */
    .tcards, .tcards tbody, .tcards tr { display: table-row-group; }
    .tcards { display: table; width: 100%; }
    .tcards tr { display: table-row; border: 0; margin: 0; }
    .tcards thead { display: table-header-group; }
    .tcards td, .tcards th { display: table-cell; }
    .tcards td::before { display: none; }

    /* Nothing scrolls on paper, and an overflow container clips what it cannot show. */
    .scroll-x { overflow: visible; }

    /* Borders, never fills: a tint prints as a grey band, or as nothing at all. */
    .card { border-color: var(--n-900); border-radius: 0; box-shadow: none; background: var(--n-0); }
    .thead th, .tcards thead th { background: none; color: var(--n-900); }

    /* Tone is colour on screen and has no meaning in black and white. */
    .money--owed, .money--paid, .money--work, .money--muted { color: var(--n-900); }
}

/* ---- Picker: a search-as-you-type field for a list too long to be a <select> ---- */

.picker { position: relative; }

/* Above the card it sits in, or the menu is clipped by the next field's row. */
.picker__menu {
    position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 40;
    max-height: 17rem; overflow-y: auto; overscroll-behavior: contain;
    padding: var(--s1);
    border: 1px solid var(--n-300); border-radius: var(--r-sm);
    background: var(--surface); box-shadow: var(--sh-md);
}

.picker__menu[hidden] { display: none; }

.picker__list { list-style: none; margin: 0; padding: 0; }

.picker__opt {
    display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3);
    min-height: var(--ctl-h-sm); padding: 6px var(--s2);
    border-radius: var(--r-sm);
    font-size: var(--ctl-fs);
    cursor: pointer;
}

/* One highlight for hover and for the keyboard, so both feel like the same control. */
.picker__opt--on { background: var(--n-100); }

.picker__opt-l { min-width: 0; overflow-wrap: anywhere; }

.picker__opt-h { flex: none; font-size: 12px; color: var(--faint); }

.picker__none { margin: 0; padding: var(--s2); font-size: 13px; color: var(--muted); }
.picker__none[hidden] { display: none; }

.picker__more {
    display: block; width: 100%;
    min-height: var(--ctl-h-sm); margin-top: var(--s1); padding: 0 var(--s2);
    border: 0; border-top: 1px solid var(--n-100); border-radius: 0;
    background: none; color: var(--brand-900);
    font: inherit; font-size: 13px; font-weight: 600;
    cursor: pointer;
}

.picker__more[hidden] { display: none; }

@media (hover: hover) {
    .picker__opt:hover { background: var(--n-100); }
    .picker__more:hover { background: var(--n-50); }
}

/* A thumb needs a taller row than a pointer does, and the menu has room for it. */
@media (pointer: coarse) {
    .picker__opt { min-height: 44px; }
    .picker__menu { max-height: 60vh; }
}

/* ---- Attachment viewer ---- */

/* Full screen on a phone, because an attachment of a window is not readable at thumbnail size and a
   new tab loses the half-filled form behind it. A dialog in the top layer, so it covers whatever is
   already open — including another dialog, which no z-index can do. */
.lb {
  max-width: none;
  max-height: none;
  width: 100vw;
  height: 100dvh;
  margin: 0;
  padding: var(--s3);
  border: 0;
  background: rgb(0 0 0 / 0.9);
}

/* Only when open: a dialog is display:none until then, and a bare display:flex would undo that.
   stretch, not center: the stage is the full height of the frame so it does not resize per attachment. */
.lb[open] {
  display: flex;
  align-items: stretch;
  justify-content: center;
  gap: var(--s2);
}

.lb::backdrop { background: rgb(0 0 0 / 0.6); }

/* The page behind must not scroll under the viewer on a touch drag. */
.lb-open, .lb-open body { overflow: hidden; }

/* A fixed stage: the box is the same size for every attachment and the picture is fitted inside it.
   Sizing the box to each attachment made the frame jump and carried the paging buttons with it, so the
   control moved out from under the thumb between one attachment and the next. */
.lb__i {
  flex: 1 1 auto;
  min-width: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: var(--r-sm);
}

/* One size for all three controls: a thumb finds them at the screen's edge without looking. */
.lb__x, .lb__p, .lb__n {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  flex: none;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgb(255 255 255 / 0.14);
  color: #fff;
  cursor: pointer;
}

.lb__x { position: absolute; top: var(--s3); right: var(--s3); }

/* The frame stretches; the controls stay centred against it rather than growing to its height. */
.lb__p, .lb__n { align-self: center; }

.lb__x:focus-visible, .lb__p:focus-visible, .lb__n:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

/* Sits clear of the image on a phone, where there is no room either side of it. */
.lb__c {
  position: absolute;
  left: 0;
  right: 0;
  bottom: var(--s3);
  margin: 0;
  text-align: center;
  color: rgb(255 255 255 / 0.75);
  font-size: 12px;
}

@media (max-width: 559.98px) {
  /* Under the picture rather than beside it: 48px each side of a 360px screen is the picture. */
  .lb { flex-wrap: wrap; padding: var(--s3) var(--s2) calc(var(--s5) + var(--s3)); }
  .lb__i { flex: 1 1 100%; min-height: 0; }
  .lb__p { position: absolute; left: var(--s2); bottom: calc(var(--s3) + 24px); }
  .lb__n { position: absolute; right: var(--s2); bottom: calc(var(--s3) + 24px); }
}

@media (hover: hover) and (pointer: fine) {
  .lb__x:hover, .lb__p:hover, .lb__n:hover { background: rgb(255 255 255 / 0.28); }
}

/* Any attachment that opens in the viewer says so on hover. Keyed on the same [data-lightbox] hook as
   the viewer itself, so a thumbnail added anywhere gets this without its own markup or styles. */
a[data-lightbox] { position: relative; }

a[data-lightbox]::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0;
  border-radius: inherit;
  background-color: rgb(0 0 0 / 0.45);
  background-repeat: no-repeat;
  background-position: center;
  background-size: 22px;

  /* The sprite's own i-eye, redrawn here: CSS cannot reach a <use> inside the sprite. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 12s3.6-7 10-7 10 7 10 7-3.6 7-10 7-10-7-10-7z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E");
  transition: opacity 0.12s ease;
}

/* Only where there is a pointer to hover with. A tap opens the attachment, so a touch device is told nothing. */
@media (hover: hover) and (pointer: fine) {
  a[data-lightbox]:hover::after { opacity: 1; }
}

/* Keyboard reaches it too, and the eye is the only thing saying what Enter will do. */
a[data-lightbox]:focus-visible::after { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  a[data-lightbox]::after { transition: none; }
}

/* ---- The error page. Sits in the sign-in shell, which needs no database to render. ---- */

/* The address asked for, so a mistyped link is obvious. */
.err__at {
    margin: 0 0 var(--s3);
    padding: var(--s2) var(--s3);
    border: 1px solid var(--line); border-radius: var(--r-sm);
    background: var(--n-25); color: var(--muted);
    font-size: 13px; word-break: break-all;
}

/* Quoted to the office, so it reads as a reference not part of the message. */
.err__ref { margin: var(--s4) 0 0; color: var(--muted); font-size: 13px; }

.err__acts { display: flex; flex-wrap: wrap; gap: var(--s2); }


/* ---- Picking rows out of a table ----------------------------------------------------------
   One control, one word, one alignment, wherever a table offers a selection: install rates, the
   claim screen, the office invoice list, its amendments and the payslips. They had three class
   sets and three words between them, which is three chances to drift.                          */

.pick-col { width: 1%; white-space: nowrap; }

/* Header and cell share one alignment. The head carries a label and the cells carry a bare
   control, so left-aligning both is what lines the ticks up down the column — centring each
   within its own cell does not, because their contents differ in width. */
.pick-col, th.pick-col { text-align: left; vertical-align: middle; }

/* Native control, not a drawn one: it stays keyboard- and screen-reader-correct for free.
   vertical-align matters even inside the flex label below: a table cell that ever renders the
   control outside .pick-all falls back to baseline, which sits a tick two pixels above the word
   beside it. Setting it here means the two screens cannot drift on that. */
.pick, .chk {
    width: 16px; height: 16px;
    flex: none; margin: 0;
    vertical-align: middle;
    accent-color: var(--brand-900);
    cursor: pointer;
}

.chk:disabled { accent-color: var(--n-400); cursor: default; }

/* Settled: the tick is there so the column reads as a column, but it is plainly not yours. */
.pick:disabled { cursor: not-allowed; opacity: .45; }

/* The tick and its word are one control, so the whole label is the target. line-height 1 on
   the pair: the inherited heading line-height gave the word a taller box than the tick, and
   centring within it left the two a pixel apart. */
.pick-all {
    display: inline-flex; align-items: center; gap: var(--s2);
    line-height: 1; cursor: pointer;
}

/* The cell holds one control and nothing else, so it centres on the row like every other cell. */
.pick-col > .pick,
.pick-col > .pick-all { vertical-align: middle; }

/* No colour of its own: it is a column heading, and inherits what every other th uses. */
.pick-all__t { color: inherit; }

/* The card layout hides the head, and with it the only select-all. Below 760px the head comes
   back carrying that one cell, so the control survives the mode installers actually use. */
@media (max-width: 760px) {
    .pick-head thead { display: block; }

    .pick-head thead tr {
        display: block;
        border: 0; background: none; margin-bottom: var(--s2); padding: 0;
    }

    .pick-head thead th { display: none; }

    .pick-head thead th.pick-col { display: block; width: auto; padding: 0; }

    /* A 16px box is a miss with a thumb: the label carries the padding, not the control. */
    .pick-all { min-height: 44px; padding: var(--s1) 0; }
}

@media (max-width: 480px) {
    .pick, .chk { width: 14px; height: 14px; }
}


/* The action and what the selection comes to, on one line above the table it acts on. A card
   in its own right, separated from the table by the same gap any two cards keep: the CRM draws
   them as two surfaces, and attaching them made the button read as part of the header row. */
.cm__bar {
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3) var(--s4);
    padding: var(--s3) var(--s4);
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
    margin-bottom: var(--s4);
}

/* Label, count and figure read together, so they centre on each other rather than sharing a
   baseline — the chip carries padding, which drops a baseline-aligned label a pixel low. */
.cm__sum { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; min-width: 0; }

.cm__k, .cm__n, .cm__v { display: inline-flex; align-items: center; }

.cm__k { font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--faint); }

.cm__n {
    font-size: 12px; font-weight: 700; color: var(--text);
    min-width: 1.4rem; padding: 1px 7px;
    border-radius: var(--r-pill); background: var(--n-100);
    text-align: center; justify-content: center;
}

/* One size for every figure on the bar: scaling one made the row look broken, not emphasised. */
.cm__v { font-size: 17px; font-weight: 680; letter-spacing: -.015em; color: var(--text); line-height: 1.2; }

.cm__v--neg { color: var(--red); }

/* Figures on one line need separating, or they read as a single run of numbers. */
.cm__sep { width: 1px; height: 1.4em; align-self: center; margin: 0 var(--s1); background: var(--line); }

/* The action finishes the row, wherever the figures end. */
.cm__act { display: flex; align-items: center; gap: var(--s2); min-width: 0; margin-left: auto; }

@media (max-width: 759px) {
    /* Stacked, and the figures lead: on a phone the total is what is being confirmed. */
    .cm__bar { gap: var(--s2); }

    .cm__sep { display: none; }

    .cm__act { flex-direction: column; align-items: stretch; width: 100%; margin-left: 0; }

    .cm__act .btn { width: 100%; }
}
