/* ==========================================================================
   app.css — the signed-in application layer, on the design.css tokens.

   design.css carries the public look (header, page header, cards, buttons,
   fields). This file adds what an admin panel and an assessor's diary need
   and nothing the public pages would use: app header, tables, badges,
   modals, toasts, forms, the week grid, the timeline.

   Same rules: white ground, one brand colour for actions, navy only as a
   dark ground, hairline borders, three radii, light headings.
   ========================================================================== */

/* ---------------------------------------------------------------- brand -- */
/* Assessor Access: the logo's navy (#022454) does every action, its gold is
   the accent on dark grounds. design.css stays untouched; its brand scale
   is replaced here, and the few rules in it that carry a colour as a
   literal rgba() are restated. Contrast: brand-700 on white 15:1,
   gold (brand-400) on navy 6.3:1. Titles are Playfair Display, the rest
   Archivo. */

/* Values are the brand kit's swatches (Assessor Access Logo Kit): navy 900
   #042656 and navy 700 #0A3068 as one flat colour for every action; gold
   300 #E9B637 on navy (5.5:1), gold 700 #966018 on light (4.8:1), gold 500
   #CA952D for decoration; ivory #F7F4EE as the default ground. The kit's
   rule: the wordmark is drawn artwork and is never set in a font. */
/* Size-matched stand-ins, so text holds its line breaks while the web fonts
   load and nothing on the page moves when they arrive. Ratios were measured
   against the real faces in Chrome. */
@font-face { font-family: "Playfair Fallback"; src: local("Georgia"); size-adjust: 100.6%; ascent-override: 107.6%; descent-override: 25%; line-gap-override: 0%; }
@font-face { font-family: "Playfair Fallback"; font-style: italic; src: local("Georgia Italic"), local("Georgia-Italic"); size-adjust: 96.8%; ascent-override: 111.8%; descent-override: 25.9%; line-gap-override: 0%; }
@font-face { font-family: "Archivo Fallback"; font-weight: 400 500; src: local("Arial"); size-adjust: 97.9%; ascent-override: 89.7%; descent-override: 21.5%; line-gap-override: 0%; }
@font-face { font-family: "Archivo Fallback"; font-weight: 600 700; src: local("Arial Bold"), local("Arial-BoldMT"); size-adjust: 94.7%; ascent-override: 92.7%; descent-override: 22.2%; line-gap-override: 0%; }
:root {
  --brand-50: #eef2f9;
  --brand-100: #dbe3f1;
  --brand-200: #b9c7e0;
  --brand-300: #8ca0bc;
  --brand-400: #e9b637; /* gold 300: kickers, icons and hairlines on navy */
  --brand-500: #1d4a8f;
  --brand-600: #0a3068; /* navy 700 */
  --brand-700: #042656; /* navy 900 */
  --brand-800: #031c42;
  --brand-900: #02132e;
  --gold: #ca952d;      /* gold 500: decoration only */
  --gold-dark: #966018; /* gold 700: gold text on light grounds */
  --gold-light: #e9b637;
  --navy: #042656;
  --navy-800: #0a3068;
  --navy-700: #123a72;
  --navy-deep: #02132e;
  --paper: #f7f4ee;     /* ivory */
  --paper-deep: #efeae0;
  --paper-warm: #f7f4ee;
  --line: #e4ded2;
  --line-strong: #cfc6b6;
  --ink: #0b1b33;
  --ink-soft: #46546a;
  --ink-faint: #5e6a79; /* 5:1 on ivory: the floor for small text */
  /* The kit's pairing: a high-contrast serif for titles, a neutral
     grotesque for everything that is read or pressed. */
  --font-brand: "Playfair Display", "Playfair Fallback", Georgia, "Times New Roman", serif;
  --font-display: "Playfair Display", "Playfair Fallback", Georgia, "Times New Roman", serif;
  --font-sans: "Archivo", "Archivo Fallback", system-ui, -apple-system, "Segoe UI", sans-serif;
}
/* Playfair's default figures are old-style and sit unevenly in times and totals. */
body { font-family: var(--font-sans); font-variant-numeric: lining-nums; }
.h-hero, .h-page, .h-section, .h-section-dark, .page-head h1 {
  font-family: var(--font-brand);
  font-weight: 500;
  letter-spacing: 0;
}
.h-hero { font-size: 2.3rem; line-height: 1.1; }
.h-page { font-size: 1.9rem; line-height: 1.15; }
.page-head h1 { font-size: 1.5rem; }
@media (min-width: 768px) {
  .h-hero { font-size: 3.2rem; }
  .h-page { font-size: 2.5rem; }
  .page-head h1 { font-size: 1.8rem; }
}
.kicker { color: var(--gold-dark); }
.page-header .kicker, .kicker--on-dark { color: var(--gold-light); }
.field:focus {
  box-shadow: 0 0 0 2px rgba(4, 38, 86, 0.18);
}
.image-slot-empty {
  background-color: var(--paper);
  background-image:
    radial-gradient(90% 80% at 100% 0%, rgba(202, 149, 45, 0.18) 0%, rgba(202, 149, 45, 0) 60%),
    radial-gradient(80% 70% at 0% 100%, rgba(4, 38, 86, 0.12) 0%, rgba(4, 38, 86, 0) 60%);
}
/* Navy is one flat colour: no gradient on the dark panels, just the tint of
   gold light the kit allows as decoration. */
.bg-brand-panel {
  background-color: var(--navy);
  background-image:
    radial-gradient(90% 80% at 100% 100%, rgba(233, 182, 55, 0.14) 0%, rgba(233, 182, 55, 0) 60%);
}
.bg-brand-band {
  background-color: var(--navy);
  background-image:
    radial-gradient(110% 90% at 100% 0%, rgba(233, 182, 55, 0.18) 0%, rgba(233, 182, 55, 0) 60%);
}
.site-footer__line {
  background: rgba(233, 182, 55, 0.75);
}

/* The header carries the drawn lockup on wide screens and the mark alone on
   phones. Both are kit artwork; nothing here is typed. */
.app-brand__lockup {
  height: 2.6rem;
  width: auto;
  display: block;
}
.app-brand__mark-img {
  display: none;
  height: 2.4rem;
  width: auto;
}
@media (max-width: 767px) {
  .app-brand__lockup { display: none; }
  .app-brand__mark-img { display: block; }
}
.brand-full {
  display: block;
  width: min(100%, 13rem);
  height: auto;
  margin: 0 auto 1.25rem;
}
.site-footer__lockup {
  display: block;
  height: 2.75rem;
  width: auto;
  margin: 0 0 1.25rem;
}

/* --------------------------------------------------------- mobile chrome -- */
/* The phone chrome is named once. Everything that must clear the bottom tab
   bar derives from these; nothing hard-codes its height. */
:root {
  --tabbar-h: 3.75rem;
  --tabbar-pb: calc(0.35rem + env(safe-area-inset-bottom));
  --safe-top: env(safe-area-inset-top);
  --safe-left: env(safe-area-inset-left);
  --safe-right: env(safe-area-inset-right);
}
html {
  -webkit-text-size-adjust: 100%;
  /* Inherited, so it also covers what has a click listener of its own: month
     cells, a table body with clickable rows, labels, summaries, the dialog
     backdrop. Taps show through the :active rules instead. */
  -webkit-tap-highlight-color: transparent;
}
button, a, input, select, textarea, label, summary, .cal__cell {
  touch-action: manipulation;
}
/* touch-action does not apply to a table row, so it goes on its cells. */
.table tr.is-clickable > td {
  touch-action: manipulation;
}

/* ------------------------------------------------------------ app shell -- */

body.app {
  background: var(--paper);
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}

.app-header {
  position: sticky;
  top: 0;
  z-index: 30;
  background: #fff;
  border-bottom: 1px solid var(--line);
  box-shadow: var(--shadow-header);
}
.app-header__inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: 3.75rem;
}
.app-brand {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.15rem;
  color: var(--navy);
  text-decoration: none;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
.app-brand__mark {
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background: var(--brand-50);
  color: var(--brand-700);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.app-brand__mark svg {
  width: 1rem;
  height: 1rem;
}
.app-brand__role {
  font-family: var(--font-sans);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--ink-faint);
  margin-left: 0.25rem;
}
.app-nav {
  display: flex;
  gap: 0.25rem;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  margin-left: 0.5rem;
}
.app-nav::-webkit-scrollbar {
  display: none;
}
.app-nav a {
  display: inline-block;
  padding: 0.5rem 0.75rem;
  border-radius: var(--radius-lg);
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--ink-soft);
  text-decoration: none;
  white-space: nowrap;
}
@media (hover: hover) and (pointer: fine) {
  .app-nav a:hover {
    background: var(--paper);
    color: var(--ink);
  }
}
.app-nav a.is-active {
  color: var(--brand-700);
  background: var(--brand-50);
}
.app-user {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  white-space: nowrap;
}
.app-user__name {
  font-size: 0.875rem;
  color: var(--ink-soft);
}
.app-user button {
  font: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--brand-700);
  background: none;
  border: 0;
  padding: 0.5rem 0;
  cursor: pointer;
}
.app-header {
  padding-top: var(--safe-top);
}
@media (max-width: 767px) {
  .app-header__inner {
    flex-wrap: wrap;
    padding-block: 0.5rem;
    min-height: 3.25rem;
  }
  .app-nav {
    order: 3;
    width: 100%;
    margin-left: -0.25rem;
  }
  .app-nav a {
    min-height: 2.75rem;
    display: inline-flex;
    align-items: center;
  }
  /* Signed-in pages use the bottom tab bar instead of the top row. */
  body.app .app-nav,
  body.app .app-user__name {
    display: none;
  }
  .app-brand__role {
    display: none;
  }
}

.app-main {
  flex: 1;
  padding-block: 1.25rem 3rem;
  padding-left: max(1.25rem, var(--safe-left));
  padding-right: max(1.25rem, var(--safe-right));
}
@media (max-width: 767px) {
  body.app .app-main {
    /* Clear the tab bar, whatever height the device gives it. */
    padding-bottom: calc(var(--tabbar-h) + var(--tabbar-pb) + 1.5rem);
  }
}
@media (min-width: 768px) {
  .app-main {
    padding-block: 2rem 4rem;
  }
}

/* -------------------------------------------------------------- tab bar -- */

.tabbar {
  display: none;
}
@media (max-width: 767px) {
  .tabbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 40;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    height: calc(var(--tabbar-h) + var(--tabbar-pb));
    padding: 0 var(--safe-right) var(--tabbar-pb) var(--safe-left);
    background: #fff;
    border-top: 1px solid var(--line);
    box-shadow: 0 -4px 16px -8px rgba(26, 35, 48, 0.15);
  }
}
.tabbar a,
.tabbar button {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.2rem;
  min-height: var(--tabbar-h);
  font: inherit;
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--ink-faint);
  text-decoration: none;
  background: none;
  border: 0;
  cursor: pointer;
}
.tabbar svg {
  width: 1.4rem;
  height: 1.4rem;
}
.tabbar .is-active {
  color: var(--brand-700);
}
.tabbar .is-active svg {
  color: var(--brand-700);
}

/* The More sheet: a full-screen list, not a cramped dropdown. */
.more-sheet {
  position: fixed;
  inset: 0;
  z-index: 45;
  background: rgba(2, 36, 84, 0.45);
  display: flex;
  align-items: flex-end;
}
.more-sheet__panel {
  width: 100%;
  background: #fff;
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  padding: 0.75rem 0 calc(var(--tabbar-pb) + 0.5rem);
  max-height: 85vh;
  overflow: auto;
}
.more-sheet__panel a,
.more-sheet__panel button {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  width: 100%;
  min-height: 3.25rem;
  padding: 0 1.25rem;
  font: inherit;
  font-size: 1.05rem;
  font-weight: 500;
  color: var(--ink);
  text-decoration: none;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--line);
  text-align: left;
  cursor: pointer;
}
.more-sheet__panel a.is-active {
  color: var(--brand-700);
}
.more-sheet__panel svg {
  width: 1.3rem;
  height: 1.3rem;
  color: var(--brand-700);
}
.more-sheet__title {
  padding: 0.5rem 1.25rem 0.75rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--ink-faint);
}

.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.25rem;
}
.page-head h1 {
  font-family: var(--font-brand);
  font-weight: 400;
  font-size: 1.75rem;
  line-height: 1.15;
  color: var(--ink);
}
.page-head p {
  margin-top: 0.25rem;
  color: var(--ink-faint);
  font-size: 0.9rem;
}
.page-head__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
@media (min-width: 768px) {
  .page-head h1 {
    font-size: 2rem;
  }
}

/* --------------------------------------------------------------- panels -- */

.panel {
  border-radius: var(--radius-xl);
  border: 1px solid var(--line);
  background: #fff;
  box-shadow: var(--shadow-card);
}
.panel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--line);
}
.panel__head h2 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.1rem;
  color: var(--ink);
}
.panel__body {
  padding: 1.25rem;
}
.panel__body--flush {
  padding: 0;
}
.panel + .panel,
.stack-lg > * + * {
  margin-top: 1.25rem;
}

.grid-main {
  display: grid;
  gap: 1.25rem;
  /* minmax(0, ...) so a wide table scrolls inside its panel instead of
     widening the column and the whole page. */
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 1024px) {
  .grid-main {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    align-items: start;
  }
  .grid-main--even {
    grid-template-columns: 1fr 1fr;
  }
}

.stats {
  display: grid;
  gap: 0.75rem;
  grid-template-columns: repeat(2, 1fr);
  margin-bottom: 1.25rem;
}
@media (min-width: 768px) {
  .stats {
    grid-template-columns: repeat(4, 1fr);
  }
}
.stat {
  display: block;
  text-decoration: none;
  border-radius: var(--radius-xl);
  border: 1px solid var(--line);
  background: #fff;
  padding: 1rem 1.25rem;
}
@media (hover: hover) and (pointer: fine) {
  .stat:hover {
    border-color: var(--line-strong);
  }
}
.stat__label {
  font-size: 0.8rem;
  color: var(--ink-faint);
}
.stat__value {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.85rem;
  line-height: 1.1;
  color: var(--ink);
  margin-top: 0.25rem;
}
.stat--attention .stat__value {
  color: var(--brand-700);
}

/* -------------------------------------------------------------- toolbar -- */

.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1rem;
}
.toolbar .field {
  width: auto;
  min-width: 10rem;
  padding: 0.6rem 0.85rem;
  font-size: 0.9rem;
}
.toolbar .field--grow {
  flex: 1 1 14rem;
}
.toolbar__spacer {
  flex: 1;
}

/* --------------------------------------------------------------- tables -- */

.table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.925rem;
}
.table th {
  text-align: left;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--ink-faint);
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.table td {
  padding: 0.8rem 1rem;
  border-bottom: 1px solid var(--line);
  color: var(--ink-soft);
  vertical-align: top;
}
.table tr:last-child td {
  border-bottom: 0;
}
.table td.is-strong,
.table .is-strong {
  color: var(--ink);
  font-weight: 600;
}
.table tr.is-clickable {
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .table tr.is-clickable:hover td {
    background: var(--paper);
  }
}
.table .nowrap {
  white-space: nowrap;
}
.table .num {
  text-align: right;
}
.table a {
  color: var(--brand-700);
  font-weight: 600;
  text-decoration: none;
}
@media (hover: hover) and (pointer: fine) {
  .table a:hover {
    text-decoration: underline;
  }
}

/* --------------------------------------------------------------- badges -- */

.badge {
  display: inline-block;
  border-radius: 9999px;
  padding: 0.2rem 0.65rem;
  /* Archivo even inside a Playfair page title. */
  font-family: var(--font-sans);
  letter-spacing: 0;
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
  background: var(--paper-deep);
  color: var(--ink-soft);
}
.badge--scheduled,
.badge--active {
  background: var(--brand-50);
  color: var(--brand-700);
}
.badge--completed {
  background: var(--brand-700);
  color: #fff;
}
.badge--no_access,
.badge--pending,
.badge--paused {
  background: #fdf3dc;
  color: #7a5200;
}
.badge--cancelled,
.badge--rejected,
.badge--offboarded {
  background: var(--danger-soft);
  color: var(--danger);
}

/* EPC band chips. The official band colours; the letter comes from data. */
.band {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-weight: 600;
  color: var(--ink);
}
.band__letter {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--radius);
  font-family: var(--font-display);
  font-weight: 600;
  color: #fff;
}
.band__letter[data-band="A"] { background: #008054; }
.band__letter[data-band="B"] { background: #19b459; }
.band__letter[data-band="C"] { background: #8dce46; color: var(--ink); }
.band__letter[data-band="D"] { background: #ffd500; color: var(--ink); }
.band__letter[data-band="E"] { background: #fcaa65; color: var(--ink); }
.band__letter[data-band="F"] { background: #ef8023; }
.band__letter[data-band="G"] { background: #e9153b; }

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

.form-grid {
  display: grid;
  gap: 1rem;
}
@media (min-width: 640px) {
  .form-grid {
    grid-template-columns: 1fr 1fr;
  }
  .form-grid .span-2 {
    grid-column: span 2;
  }
}
textarea.field {
  min-height: 6rem;
  resize: vertical;
}
select.field {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%2347525e' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.9rem center;
  padding-right: 2.5rem;
}
/* iOS fades disabled text on its own; the fill colour and opacity keep it
   readable. Read-only fields look the same but can still be scrolled and
   copied. */
.field:disabled,
.field[readonly] {
  background: var(--paper);
  color: var(--ink-soft);
  -webkit-text-fill-color: var(--ink-soft);
  opacity: 1;
}
.field.is-invalid {
  border-color: var(--danger);
}
.help {
  margin-top: 0.35rem;
  font-size: 0.8rem;
  color: var(--ink-faint);
}
.form-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 1.25rem;
}
.form-error {
  color: var(--danger);
  font-size: 0.9rem;
  margin-top: 0.75rem;
}
.form-error:empty {
  display: none;
}
.checkbox {
  display: flex;
  gap: 0.6rem;
  align-items: flex-start;
  font-size: 0.925rem;
  color: var(--ink-soft);
  cursor: pointer;
}
.checkbox input {
  flex: none; /* a two-line label must not squash the box */
  margin-top: 0.3rem;
  width: 1.05rem;
  height: 1.05rem;
  accent-color: var(--brand-700);
}
.btn-danger {
  background: #fff;
  color: var(--danger);
  border-color: var(--danger);
}
@media (hover: hover) and (pointer: fine) {
  .btn-danger:hover {
    background: var(--danger-soft);
  }
}
.btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* ------------------------------------------------------- phone ergonomics -- */
/* Layout for phones only. The sizes (16px fields, 52px fields, 44px
   targets) live in the touch sizing block of the "Touch and iOS layer" at
   the end of this file, which also covers tablets and touch screens. */
@media (max-width: 767px) {
  .page-head__actions .btn {
    flex: 1 1 auto;
    justify-content: center;
  }
  .form-actions .btn {
    flex: 1 1 auto;
    justify-content: center;
  }
  .job-card__actions .btn {
    flex: 1 1 calc(50% - 0.25rem);
    justify-content: center;
  }
  /* Tables become cards on a phone (the page supplies both). */
  .desktop-only {
    display: none !important;
  }
}
/* Signed-in pages keep the cards up to 1023px, the same line as the tab
   bar, so a tablet never gets a table wider than its screen. */
@media (max-width: 1023px) {
  body.app .desktop-only {
    display: none !important;
  }
}
@media (min-width: 768px) {
  body:not(.app) .mobile-only {
    display: none !important;
  }
}
@media (min-width: 1024px) {
  body.app .mobile-only {
    display: none !important;
  }
}

/* The screen's one job, pinned under the thumb on a phone; back in the flow
   on desktop. The page's bottom padding keeps the last row clear of it (see
   "keyboard and modal" in the Touch and iOS layer). */
@media (max-width: 767px) {
  .form-actions--sticky {
    position: fixed;
    left: 0;
    right: 0;
    bottom: calc(var(--tabbar-h) + var(--tabbar-pb));
    z-index: 35;
    margin: 0;
    padding: 0.6rem max(1rem, var(--safe-right)) 0.6rem max(1rem, var(--safe-left));
    background: #fff;
    border-top: 1px solid var(--line);
    box-shadow: 0 -4px 16px -8px rgba(26, 35, 48, 0.15);
  }
}

/* Card list that stands in for a table on a phone. */
.card-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.card-list > li {
  border-bottom: 1px solid var(--line);
}
.card-list > li:last-child {
  border-bottom: 0;
}
.card-list a.card-row {
  display: block;
  padding: 0.9rem 1.25rem;
  text-decoration: none;
  color: inherit;
}
.card-row__top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
}
.card-row__title {
  font-weight: 600;
  color: var(--ink);
}
.card-row__line {
  margin-top: 0.2rem;
  font-size: 0.9rem;
  color: var(--ink-soft);
}
.card-row__meta {
  margin-top: 0.2rem;
  font-size: 0.8rem;
  color: var(--ink-faint);
}
.btn--xs {
  padding: 0.4rem 0.9rem;
  font-size: 0.8rem;
}
.btn-link {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-weight: 600;
  color: var(--brand-700);
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .btn-link:hover {
    text-decoration: underline;
  }
}
/* Not rendered at all, so AutoFill and the iOS form arrows cannot reach it. */
.honeypot {
  display: none;
}

/* ----------------------------------------------------------- definition -- */

.defs {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.5rem 1.25rem;
  font-size: 0.925rem;
}
.defs dt {
  color: var(--ink-faint);
}
.defs dd {
  margin: 0; /* the browser's 40px dd indent was eating the value column */
  color: var(--ink);
  min-width: 0;
  overflow-wrap: anywhere;
}
.defs a {
  color: var(--brand-700);
  font-weight: 600;
  text-decoration: none;
}

/* ---------------------------------------------------------------- lists -- */

.list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.list > li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.85rem 1.25rem;
  border-bottom: 1px solid var(--line);
  font-size: 0.925rem;
}
.list > li:last-child {
  border-bottom: 0;
}
.list a.is-strong {
  color: var(--ink);
  font-weight: 600;
  text-decoration: none;
}
@media (hover: hover) and (pointer: fine) {
  .list a.is-strong:hover {
    color: var(--brand-700);
  }
}
.list__meta {
  font-size: 0.8rem;
  color: var(--ink-faint);
  margin-top: 0.15rem;
}
.empty {
  padding: 2rem 1.25rem;
  text-align: center;
  color: var(--ink-faint);
  font-size: 0.925rem;
}

/* --------------------------------------------------------- job cards --- */

.job-card {
  border-radius: var(--radius-xl);
  border: 1px solid var(--line);
  background: #fff;
  box-shadow: var(--shadow-card);
  padding: 1.1rem 1.25rem;
}
.job-card + .job-card {
  margin-top: 0.85rem;
}
.job-card__top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}
.job-card__time {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.5rem;
  color: var(--ink);
}
.job-card__address {
  margin-top: 0.35rem;
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--ink);
}
.job-card__meta {
  margin-top: 0.2rem;
  color: var(--ink-soft);
  font-size: 0.925rem;
}
/* A phone number or date in the line wraps whole, never split in two. */
.job-card__meta .nowrap {
  white-space: nowrap;
}
.job-card__notes {
  margin-top: 0.6rem;
  padding: 0.6rem 0.8rem;
  background: var(--paper);
  border-radius: var(--radius-lg);
  font-size: 0.9rem;
  color: var(--ink-soft);
  white-space: pre-wrap;
}
.job-card__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.9rem;
}
body.app--assessor .btn {
  min-height: 2.75rem;
}

/* ----------------------------------------------------------- timeline -- */

.timeline {
  list-style: none;
  margin: 0;
  padding: 0;
}
.timeline li {
  position: relative;
  padding: 0 0 1rem 1.5rem;
  font-size: 0.9rem;
  color: var(--ink-soft);
}
.timeline li::before {
  content: "";
  position: absolute;
  left: 0.3rem;
  top: 0.35rem;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background: var(--brand-400);
}
.timeline li::after {
  content: "";
  position: absolute;
  left: 0.57rem;
  top: 1rem;
  bottom: 0;
  width: 1px;
  background: var(--line);
}
.timeline li:last-child::after {
  display: none;
}
.timeline__when {
  display: block;
  font-size: 0.78rem;
  color: var(--ink-faint);
}

/* ------------------------------------------------------------ week grid -- */

.cal-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1rem;
}
.cal-toolbar__label {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.2rem;
  color: var(--ink);
  margin-inline: 0.5rem;
}
.cal {
  display: grid;
  gap: 0.5rem;
}
@media (min-width: 1024px) {
  .cal {
    grid-template-columns: repeat(7, minmax(0, 1fr));
  }
}
.cal__day {
  border-radius: var(--radius-xl);
  border: 1px solid var(--line);
  background: #fff;
  min-height: 7rem;
  display: flex;
  flex-direction: column;
}
.cal__day.is-past {
  background: var(--paper);
}
.cal__day.is-weekend .cal__head {
  color: var(--ink-faint);
}
.cal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.6rem 0.8rem;
  border-bottom: 1px solid var(--line);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink);
}
.cal__head .day-num {
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 500;
}
.cal__day.is-today .cal__head {
  color: var(--brand-700);
}
.cal__day.is-today .day-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 50%;
  background: var(--brand-700);
  color: #fff;
}
.cal__items {
  padding: 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  flex: 1;
}
.cal__item {
  display: block;
  width: 100%;
  text-align: left;
  border: 1px solid var(--brand-200);
  border-left: 3px solid var(--brand-700);
  background: var(--brand-50);
  border-radius: var(--radius-lg);
  padding: 0.45rem 0.6rem;
  font: inherit;
  font-size: 0.8rem;
  line-height: 1.35;
  color: var(--ink);
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .cal__item:hover {
    border-color: var(--brand-600);
  }
}
.cal__item strong {
  display: block;
  font-size: 0.85rem;
}
.cal__item span {
  color: var(--ink-soft);
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cal__item--completed {
  background: #fff;
  border-color: var(--line);
  border-left-color: var(--brand-400);
  color: var(--ink-soft);
}
.cal__item--no_access {
  background: #fdf3dc;
  border-color: #f2dea6;
  border-left-color: #c98a00;
}
.cal__item--cancelled {
  background: var(--danger-soft);
  border-color: #f6c9c5;
  border-left-color: var(--danger);
  text-decoration: line-through;
}
.cal__item--block {
  background: var(--paper-deep);
  border: 1px dashed var(--line-strong);
  border-left: 3px solid var(--ink-faint);
  color: var(--ink-soft);
}
.cal__add {
  margin-top: auto;
  padding: 0.5rem;
}
.cal__add button {
  width: 100%;
  font: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--brand-700);
  background: none;
  border: 1px dashed var(--brand-200);
  border-radius: var(--radius-lg);
  padding: 0.4rem;
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .cal__add button:hover {
    background: var(--brand-50);
  }
}
/* Under 1024px the week is one column. An empty day is just its heading,
   so the week fits, and the chosen day can be brought into view. */
@media (max-width: 1023px) {
  .cal--week .cal__day {
    min-height: 0;
    scroll-margin-top: calc(var(--safe-top) + 4.5rem);
  }
  /* The rule under the heading moves to the entries, so an empty day has
     no line left at its rounded foot. */
  .cal--week .cal__head {
    border-bottom: 0;
  }
  .cal--week .cal__items {
    border-top: 1px solid var(--line);
  }
  .cal--week .cal__items:empty {
    display: none;
  }
}
/* While the next week or month loads, the old one fades so it is not
   read under the new label. */
.cal[aria-busy="true"] {
  opacity: 0.5;
  transition: opacity 0.2s;
}

/* ----------------------------------------------------------- month grid -- */

.seg {
  display: inline-flex;
  border: 1px solid var(--line-strong);
  border-radius: 9999px;
  overflow: hidden;
  background: #fff;
}
.seg__btn {
  font: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  padding: 0.4rem 0.9rem;
  border: 0;
  background: none;
  color: var(--ink-soft);
  cursor: pointer;
}
.seg__btn.is-active {
  background: var(--brand-700);
  color: #fff;
}
.cal--month {
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 0.25rem;
}
.cal__dow {
  text-align: center;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--ink-faint);
  padding: 0.25rem 0;
}
.cal__cell {
  border-radius: var(--radius-lg);
  border: 1px solid var(--line);
  background: #fff;
  min-height: 6.5rem;
  display: flex;
  flex-direction: column;
  cursor: pointer;
}
.cal__cell.is-past {
  background: var(--paper);
}
.cal__cell.is-other {
  opacity: 0.45;
}
.cal__cell.is-today {
  border-color: var(--brand-400);
}
.cal__cell-head {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem 0.45rem 0.1rem;
}
.cal__cell-head .day-num {
  font: inherit;
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--ink);
  background: none;
  border: 0;
  padding: 0.1rem 0.35rem;
  border-radius: 9999px;
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .cal__cell-head .day-num:hover {
    background: var(--paper-deep);
  }
}
.cal__cell.is-today .day-num {
  background: var(--brand-700);
  color: #fff;
}
.cal__count {
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--brand-700);
  background: var(--brand-50);
  border-radius: 9999px;
  padding: 0.05rem 0.45rem;
}
.cal__plus {
  margin-left: auto;
  font: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  border: 1px dashed var(--brand-200);
  background: none;
  color: var(--brand-700);
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .cal__plus:hover {
    background: var(--brand-50);
  }
}
.cal--month .cal__items {
  padding: 0.25rem 0.35rem 0.35rem;
  gap: 0.25rem;
}
.cal--month .cal__item {
  padding: 0.25rem 0.45rem;
  font-size: 0.72rem;
  border-left-width: 3px;
}
.cal__more {
  font: inherit;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--brand-700);
  background: none;
  border: 0;
  text-align: left;
  padding: 0.1rem 0.2rem;
  cursor: pointer;
}
/* The compact month (numbers and counts only) is for phone widths; from
   640px, an iPad mini or a phone on its side, the cells list entries. */
@media (max-width: 639px) {
  .cal__cell {
    min-height: 3.4rem;
  }
  .cal--month .cal__items,
  .cal__plus {
    display: none;
  }
  .cal__cell-head {
    flex-direction: column;
    align-items: center;
    gap: 0.15rem;
    padding-top: 0.4rem;
  }
}

.badge--accepted {
  background: var(--brand-100);
  color: var(--brand-800);
}
.cal__item--accepted {
  border-left-color: var(--brand-400);
}
.dist {
  font-size: 0.8rem;
  color: var(--ink-faint);
  white-space: nowrap;
}
.dist--out {
  color: var(--danger);
}

/* ---------------------------------------------------------------- modal -- */

.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: rgba(13, 27, 42, 0.55);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0;
}
@media (min-width: 640px) {
  .modal-backdrop {
    align-items: center;
    /* A phone on its side is over 640px wide: keep a wide dialog clear of
       the sensor housing and the rounded corners. */
    padding: 1.5rem max(1.5rem, var(--safe-right)) 1.5rem max(1.5rem, var(--safe-left));
  }
}
.modal {
  width: 100%;
  max-width: 34rem;
  max-height: 92vh;
  max-height: 92dvh;
  overflow: auto;
  background: #fff;
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  box-shadow: var(--shadow-lift);
  padding: 1.5rem 1.25rem calc(1.25rem + env(safe-area-inset-bottom));
}
/* The buttons stay in view at the foot of a long dialog on phones, tablets,
   touch screens and short screens (a phone on its side). The offsets match
   .modal's padding, which is the same at every width. */
@media (max-width: 1023px), (max-height: 540px), (pointer: coarse) {
  .modal__actions {
    position: sticky;
    bottom: calc(-1.25rem - env(safe-area-inset-bottom));
    margin: 1.25rem -1.25rem calc(-1.25rem - env(safe-area-inset-bottom));
    padding: 0.75rem 1.25rem calc(0.75rem + env(safe-area-inset-bottom));
    background: #fff;
    border-top: 1px solid var(--line);
  }
}
/* Buttons fill the row only in the bottom sheet; from 640px the dialog is a
   centred card and they sit at the right, as on a desktop. */
@media (max-width: 639px) {
  .modal__actions .btn {
    flex: 1 1 auto;
    justify-content: center;
  }
}
@media (min-width: 640px) {
  .modal {
    border-radius: var(--radius-xl);
  }
}
.modal--wide {
  max-width: 52rem;
}
.modal__title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.3rem;
  color: var(--ink);
  margin-bottom: 1rem;
}
.modal__body {
  font-size: 0.95rem;
  color: var(--ink-soft);
}
.modal__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 1.5rem;
}

/* ---------------------------------------------------------------- toast -- */

.toast-host {
  position: fixed;
  left: 50%;
  bottom: calc(1.25rem + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  width: min(92vw, 28rem);
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  cursor: pointer;
  touch-action: manipulation;
  background: var(--navy);
  color: #fff;
  border-radius: var(--radius-lg);
  padding: 0.8rem 1rem;
  font-size: 0.9rem;
  box-shadow: var(--shadow-lift);
  animation: toast-in 0.2s ease-out;
}
.toast--success {
  background: var(--brand-700);
}
.toast--error {
  background: var(--danger);
}
@media (max-width: 767px) {
  body.app .toast-host {
    bottom: calc(var(--tabbar-h) + var(--tabbar-pb) + 0.75rem);
  }
}
@keyframes toast-in {
  from {
    opacity: 0;
    transform: translateY(0.5rem);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ------------------------------------------------------------ auth card -- */

.auth-wrap {
  min-height: calc(100vh - 3.75rem);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem 1.25rem;
}
.auth-card {
  width: 100%;
  max-width: 26rem;
}
.auth-card h1 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.6rem;
  color: var(--ink);
}

/* ------------------------------------------------------------ utilities -- */

.muted {
  color: var(--ink-faint);
}
.text-right {
  text-align: right;
}
.text-sm {
  font-size: 0.875rem;
}
.w-full {
  width: 100%;
}
.mb-2 {
  margin-bottom: 0.5rem;
}
.mb-4 {
  margin-bottom: 1rem;
}
.mb-6 {
  margin-bottom: 1.5rem;
}
.inline-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1rem;
  font-size: 0.875rem;
  color: var(--ink-soft);
}
.config-warning {
  background: var(--danger-soft);
  color: var(--danger);
  border-bottom: 1px solid #f6c9c5;
  padding: 0.75rem 1.25rem;
  font-size: 0.9rem;
  text-align: center;
}
.skeleton {
  color: var(--ink-faint);
  font-size: 0.9rem;
  padding: 1.25rem;
}

/* ==========================================================================
   Polish layer (September 2026 overhaul). Same tokens, more care: glass
   header, dot badges, stat cards, quieter calendar, entrance motion,
   shimmer loaders. Motion is CSS-only here; the public site uses the
   Motion library (assets/js/fx.js).
   ========================================================================== */

:root {
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --shadow-card: 0 1px 2px rgba(4, 38, 86, 0.04), 0 10px 30px -14px rgba(4, 38, 86, 0.14);
  --shadow-lift: 0 30px 70px -24px rgba(4, 38, 86, 0.32);
}
body.app { -webkit-font-smoothing: antialiased; color: var(--ink-soft); }

/* header */
.app-header {
  background: rgba(255, 255, 255, 0.86);
  -webkit-backdrop-filter: saturate(1.4) blur(14px);
  backdrop-filter: saturate(1.4) blur(14px);
  box-shadow: none;
  border-bottom: 1px solid var(--line);
}
.app-header__inner { min-height: 4.25rem; }
.app-nav a { border-radius: 9999px; padding: 0.5rem 0.95rem; transition: background-color 0.2s, color 0.2s; }
.app-nav a.is-active { background: var(--navy); color: #fff; }
.app-brand__role {
  border: 1px solid var(--line-strong);
  border-radius: 9999px;
  padding: 0.15rem 0.6rem;
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gold-dark);
}
.app-user button { border: 1px solid var(--line-strong); border-radius: 9999px; padding: 0.45rem 0.95rem; transition: border-color 0.2s, background-color 0.2s; }
@media (hover: hover) and (pointer: fine) {
  .app-user button:hover { border-color: var(--navy); background: var(--brand-50); }
}

/* entrance */
@media (prefers-reduced-motion: no-preference) {
  /* backwards, not both: a transform kept after the animation would make each
     block the frame for the pinned action bars inside it (position: fixed),
     pinning them over the form instead of to the screen. Backwards drops the
     transform only once the animation has finished; see the fade rule below
     for blocks with pinned bars. */
  .app-main > * { animation: rise 0.7s var(--ease) backwards; }
  .app-main > *:nth-child(2) { animation-delay: 0.06s; }
  .app-main > *:nth-child(3) { animation-delay: 0.12s; }
  .app-main > *:nth-child(4) { animation-delay: 0.18s; }
  .app-main > *:nth-child(n + 5) { animation-delay: 0.24s; }
  .modal { animation: rise 0.4s var(--ease) both; }
  .modal-backdrop { animation: fade 0.25s ease both; }
}
@keyframes rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: no-preference) and (max-width: 767px) {
  /* Opacity only for a block that holds a pinned action bar: any transform,
     even mid-animation, makes the block the frame for position: fixed, so
     the bar would sit inside the block and then jump to the screen. */
  .app-main > :has(.form-actions--sticky) { animation-name: fade; }
}

/* buttons */
.btn { font-family: var(--font-sans); transition: background-color 0.2s, color 0.2s, border-color 0.2s, transform 0.2s var(--ease); }
.btn:active { transform: scale(0.98); }
@media (hover: hover) and (pointer: fine) {
  .btn-outline:hover { border-color: var(--navy); }
}
/* design.css gives its button hovers to every screen, and a touch screen
   keeps :hover on the last thing tapped (a Call or Maps button after the
   call sheet, a red Delete turning grey). Without a mouse, put the resting
   look back: the exact opposite of the gate used for every hover here. */
@media not all and (hover: hover) and (pointer: fine) {
  .btn-primary:hover { background: var(--brand-700); }
  .btn-outline:hover { background: #fff; border-color: var(--line-strong); }
  .btn-outline.btn-outline-danger:hover { border-color: rgba(180, 35, 24, 0.45); }
}
/* A tap still shows while the finger is down (ui.js adds the touchstart
   listener iOS needs for :active). */
.btn-outline:active { background: var(--paper); }

/* page head */
.page-head { margin-bottom: 1.75rem; }
.page-head p { font-size: 0.95rem; }

/* panels */
.panel { border-radius: var(--radius-xl); box-shadow: var(--shadow-card); }
.panel__head { padding: 1.1rem 1.5rem; }
.panel__head h2 { font-size: 1.2rem; color: var(--navy); }
.panel__body { padding: 1.5rem; }
.panel__body--flush { padding: 0; }
.list > li { padding: 1rem 1.5rem; transition: background-color 0.2s; }
@media (hover: hover) and (pointer: fine) {
  .list > li:hover { background: var(--paper); }
}
.list > li:last-child { border-bottom-left-radius: var(--radius-xl); border-bottom-right-radius: var(--radius-xl); }

/* stats */
.stats { gap: 1rem; margin-bottom: 1.5rem; }
.stat {
  position: relative;
  padding: 1.25rem 1.5rem 1.35rem;
  box-shadow: var(--shadow-card);
  transition: transform 0.35s var(--ease), box-shadow 0.35s var(--ease), border-color 0.3s;
  overflow: hidden;
}
@media (hover: hover) and (pointer: fine) {
  .stat:hover { transform: translateY(-3px); box-shadow: 0 1px 2px rgba(4, 38, 86, 0.04), 0 22px 44px -22px rgba(4, 38, 86, 0.26); border-color: var(--line-strong); }
}
.stat__label { font-size: 0.85rem; color: var(--ink-faint); display: flex; align-items: center; gap: 0.6rem; }
.stat__label::before {
  content: "";
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  background: var(--line-strong);
  flex: none;
}
.stat__value { font-family: var(--font-display); font-weight: 600; font-size: 2.4rem; margin-top: 0.5rem; color: var(--navy); }
.stat--attention .stat__label::before { background: var(--gold); box-shadow: 0 0 0 4px rgba(202, 149, 45, 0.18); }
.stat--attention .stat__value { color: var(--navy); }
.stat--attention::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 3px;
  background: var(--gold);
}

/* badges: a dot and a label */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25rem 0.7rem 0.25rem 0.6rem;
  background: #fff;
  border: 1px solid var(--line-strong);
  color: var(--ink-soft);
  font-size: 0.76rem;
}
.badge::before { content: ""; width: 0.45rem; height: 0.45rem; border-radius: 50%; background: var(--ink-faint); flex: none; }
.badge--scheduled, .badge--active { background: var(--brand-50); border-color: var(--brand-200); color: var(--navy); }
.badge--scheduled::before, .badge--active::before { background: var(--navy); }
.badge--accepted { background: #fff; border-color: var(--brand-200); color: var(--navy); }
.badge--accepted::before { background: var(--gold); }
.badge--completed { background: var(--navy); border-color: var(--navy); color: #fff; }
.badge--completed::before { background: var(--gold-light); }
.badge--no_access, .badge--pending, .badge--paused { background: #fdf6e3; border-color: #ecd9a6; color: #7a5200; }
.badge--no_access::before, .badge--pending::before, .badge--paused::before { background: var(--gold); }
.badge--cancelled, .badge--rejected, .badge--offboarded { background: var(--danger-soft); border-color: #f3c9c4; color: var(--danger); }
.badge--cancelled::before, .badge--rejected::before, .badge--offboarded::before { background: var(--danger); }

/* tables */
.table th { background: var(--paper); font-size: 0.76rem; letter-spacing: 0.06em; text-transform: uppercase; padding: 0.85rem 1.25rem; }
.table td { padding: 1rem 1.25rem; }
.table tr.is-clickable td { transition: background-color 0.2s; }
.table a { color: var(--navy); }
.card-row__title { color: var(--navy); }

/* toolbar */
.toolbar .field { border-radius: 9999px; padding-inline: 1.1rem; background-color: #fff; }
.toolbar select.field { padding-right: 2.5rem; }

/* job cards */
.job-card { position: relative; padding: 1.35rem 1.5rem; transition: transform 0.35s var(--ease), box-shadow 0.35s var(--ease); overflow: hidden; }
.job-card::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--gold); }
@media (hover: hover) and (pointer: fine) {
  .job-card:hover { transform: translateY(-2px); box-shadow: 0 1px 2px rgba(4, 38, 86, 0.04), 0 22px 44px -22px rgba(4, 38, 86, 0.26); }
}
.job-card__time { font-weight: 600; font-size: 1.75rem; color: var(--navy); }
.job-card__address { font-size: 1.1rem; }
.job-card__notes { border: 1px solid var(--line); }

/* calendar */
.cal-toolbar__label { font-size: 1.35rem; color: var(--navy); }
.cal__cell { transition: border-color 0.2s, box-shadow 0.25s; }
@media (hover: hover) and (pointer: fine) {
  .cal__cell:hover { border-color: var(--line-strong); box-shadow: var(--shadow-card); }
}
.cal__cell.is-today { border-color: var(--gold); box-shadow: 0 0 0 1px var(--gold); }
.cal__day.is-today { border-color: var(--gold); box-shadow: 0 0 0 1px var(--gold); }
.cal__day.is-today .cal__head { color: var(--navy); }
.cal__plus { transition: opacity 0.2s, background-color 0.2s; border-style: solid; border-color: var(--line-strong); }
/* With a mouse the plus appears on hover; a touch screen has no hover, so
   there it always shows. */
@media (hover: hover) and (pointer: fine) {
  .cal__plus { opacity: 0; }
  .cal__cell:hover .cal__plus, .cal__plus:focus-visible { opacity: 1; }
}
.cal__count { background: var(--navy); color: #fff; }
.cal__item { transition: transform 0.2s var(--ease), border-color 0.2s; }
@media (hover: hover) and (pointer: fine) {
  .cal__item:hover { transform: translateX(2px); }
}
.cal__dow { text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.7rem; }
.seg { border-color: var(--line-strong); }

/* timeline */
.timeline li::before { background: #fff; border: 2px solid var(--gold); width: 0.7rem; height: 0.7rem; left: 0.2rem; top: 0.3rem; box-sizing: border-box; }
.timeline li:first-child::before { background: var(--gold); }

/* loaders */
.skeleton {
  position: relative;
  color: transparent !important;
  min-height: 3.5rem;
  border-radius: var(--radius-lg);
  background: linear-gradient(100deg, var(--paper) 30%, #fff 50%, var(--paper) 70%) 0 0 / 200% 100%;
  animation: shimmer 1.4s linear infinite;
}
@keyframes shimmer { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .skeleton { animation: none; } }

/* empty states */
.empty { padding: 2.75rem 1.5rem; font-size: 0.95rem; }

/* tab bar */
.tabbar { -webkit-backdrop-filter: saturate(1.4) blur(14px); backdrop-filter: saturate(1.4) blur(14px); background: rgba(255, 255, 255, 0.92); }
.tabbar a, .tabbar button { position: relative; transition: color 0.2s; }
.tabbar .is-active::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: 2rem;
  height: 3px;
  border-radius: 0 0 3px 3px;
  background: var(--gold);
  transform: translateX(-50%);
}

/* fields */
.field { transition: border-color 0.2s, box-shadow 0.2s, background-color 0.2s; }
@media (hover: hover) and (pointer: fine) {
  .field:hover { border-color: #b9ae9a; }
}
.label { color: var(--ink); letter-spacing: 0.005em; }

/* ==========================================================================
   Navigation by width (28 September 2026)

   The assessor nav has six items. Squeezed next to a long name or email it
   used to scroll out of sight under the user block, so "Account" was cut off.
   Now the nav never shrinks; the name gives way first (ellipsis, then hidden
   when there is no useful room), the lockup drops to the mark below 1280px,
   and tablets in portrait (768-1023px, iPad) get the phone's bottom tab bar
   instead of a top row that cannot fit.
   ========================================================================== */
@media (min-width: 1024px) {
  .app-nav { flex: 0 0 auto; overflow: visible; }
  .app-user {
    flex: 1 1 0;
    min-width: 0;
    justify-content: flex-end;
    container-type: inline-size;
  }
  .app-user__name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* Fewer than about ten characters of name is not worth showing. */
  @container (max-width: 11rem) {
    .app-user__name { display: none; }
  }
}
@media (min-width: 1024px) and (max-width: 1279px) {
  .app-brand__lockup { display: none; }
  .app-brand__mark-img { display: block; }
}
@media (min-width: 768px) and (max-width: 1023px) {
  body.app .app-nav,
  body.app .app-user__name { display: none; }
  .tabbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 40;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    height: calc(var(--tabbar-h) + var(--tabbar-pb));
    /* Keep the four items together in the middle rather than at the far
       edges of a tablet. */
    padding: 0 max(var(--safe-right), calc((100% - 36rem) / 2)) var(--tabbar-pb) max(var(--safe-left), calc((100% - 36rem) / 2));
    border-top: 1px solid var(--line);
    box-shadow: 0 -4px 16px -8px rgba(26, 35, 48, 0.15);
  }
  body.app .app-main { padding-bottom: calc(var(--tabbar-h) + var(--tabbar-pb) + 2rem); }
  body.app .toast-host { bottom: calc(var(--tabbar-h) + var(--tabbar-pb) + 0.75rem); }
  .more-sheet { justify-content: center; }
  .more-sheet__panel { max-width: 36rem; }
}

/* ==========================================================================
   Deleting jobs (28 September 2026)
   A quiet "danger zone" at the foot of the job's Record panel, a typed
   confirmation dialog (ui.confirmTyped), and a select mode on the jobs list.
   ========================================================================== */
.danger-zone {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1.25rem;
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
}
.danger-zone strong { display: block; color: var(--ink); font-weight: 600; font-size: 0.95rem; }
.danger-zone p { margin-top: 0.15rem; font-size: 0.85rem; color: var(--ink-faint); max-width: 34ch; }
.btn-outline-danger { color: var(--danger); border-color: rgba(180, 35, 24, 0.45); }
@media (hover: hover) and (pointer: fine) {
  .btn-outline-danger:hover { background: var(--danger-soft); border-color: var(--danger); }
}
.btn-danger:disabled { background: #fff; }
.typed-word { color: var(--danger); font-weight: 700; letter-spacing: 0.02em; }
.typed-field.is-valid { border-color: var(--danger); box-shadow: 0 0 0 2px rgba(180, 35, 24, 0.14); }

/* Select mode on the jobs list. The tick column only exists while selecting. */
.sel-cell { display: none; width: 3rem; }
.is-selecting .sel-cell { display: table-cell; }
.sel-cell input,
.sel-box input { width: 1.25rem; height: 1.25rem; accent-color: var(--danger); cursor: pointer; }
.is-selecting tr.is-selected td { background: var(--danger-soft); }
.card-sel { display: block; }
.sel-box { display: none; }
.is-selecting .card-sel { display: grid; grid-template-columns: 3.25rem minmax(0, 1fr); }
.is-selecting .sel-box { display: flex; align-items: center; justify-content: center; min-height: 3.5rem; cursor: pointer; }
.is-selecting .card-sel.is-selected { background: var(--danger-soft); }
.is-selecting .card-sel .card-row { padding-left: 0; }
.is-selecting tr.is-clickable { cursor: default; }

.selbar {
  position: sticky;
  bottom: 1rem;
  z-index: 25;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1rem;
  padding: 0.75rem 0.75rem 0.75rem 1.25rem;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 9999px;
  box-shadow: 0 18px 40px -18px rgba(4, 38, 86, 0.35);
}
.selbar[hidden] { display: none; }
.selbar__count { margin-right: auto; font-weight: 600; color: var(--ink); font-size: 0.95rem; }
@media (max-width: 1023px) {
  /* Phones and tablets: pinned above the tab bar, full width. */
  .selbar {
    position: fixed;
    left: max(0.75rem, var(--safe-left));
    right: max(0.75rem, var(--safe-right));
    bottom: calc(var(--tabbar-h) + var(--tabbar-pb) + 0.75rem);
    margin: 0;
    border-radius: var(--radius-xl);
  }
  body.has-selbar .app-main { padding-bottom: calc(var(--tabbar-h) + var(--tabbar-pb) + 6rem); }
}
/* Selecting on the Jobs list: the pinned bar holds every action, so toasts
   go to the top instead of over Smart book, Unassign or Delete. */
@media (max-width: 1023px) {
  body.has-selbar .toast-host {
    top: calc(var(--safe-top) + 0.75rem);
    bottom: auto;
  }
}
.field-msg { margin-top: 0.35rem; color: var(--danger); font-weight: 500; }

/* ==========================================================================
   Touch and iOS layer, 28 September 2026

   What an iPhone or iPad needs that a mouse screen does not, in one place.
   Breakpoints: phones up to 767px; tablets 768-1023px, which have the
   bottom tab bar and (on signed-in pages) cards instead of tables; desktop
   from 1024px. Touch sizing has a query of its own, every screen under
   1024px and every touch screen at any width, and carries sizes only:
   phone layout (buttons filling a row) stays in the 767px blocks.

   Classes the page scripts use: .table--stack, .list--links,
   .list--actions, .table--assessors, .form-grid__spacer,
   .order-first-narrow. Body states set by ui.js: kb-open (a field has
   focus on a touch screen, so the keyboard is up) and modal-open.
   ========================================================================== */

/* The hidden attribute always hides, whatever display a component sets. */
[hidden] {
  display: none !important;
}

/* ----------------------------------------------------------- touch sizing */
/* 16px in fields, or iOS zooms the page when one is focused. Fields 52px
   tall and nothing tappable under 44px, because they are hit on the move. */
@media (max-width: 1023px), (pointer: coarse) {
  .field,
  select.field,
  textarea.field {
    font-size: 16px;
    min-height: 3.25rem;
  }
  textarea.field {
    min-height: 6rem;
  }
  .toolbar .field {
    font-size: 16px;
    min-height: 2.75rem;
  }
  .btn,
  .btn--sm,
  .btn--xs,
  .btn-link,
  .seg__btn,
  .cal__item,
  .cal__more,
  .cal__add button,
  .app-user button,
  .app-nav a,
  .app-brand {
    min-height: 2.75rem;
  }
  .app-brand {
    min-width: 2.75rem;
  }
  .app-nav a {
    display: inline-flex;
    align-items: center;
  }
  /* A short text button ("Edit") still gets a 44px square. In a panel head
     its text stays against the right edge. */
  .btn-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.75rem;
  }
  .panel__head .btn-link {
    justify-content: flex-end;
  }
  .checkbox {
    min-height: 2.75rem;
    align-items: center;
  }
  .checkbox input {
    width: 1.35rem;
    height: 1.35rem;
    margin-top: 0;
  }
  /* A phone number or email in a details list: the padding widens the
     target to 44px without moving the text (inline padding takes no room). */
  .defs dd > a:only-child:not(.btn) {
    padding-block: 0.875rem;
  }
  /* Two or three numbers (ui.phoneLinks joins them with <br>), or a number
     under the customer's name in the diary dialog: each is its own 44px
     line, so a tap cannot ring the one above or below. A lone link keeps
     the padding above. The first of several is lifted so its text stays
     level with its label; its target reaches up into that plain text. */
  .defs dd > a[href^="tel:"]:not(:only-child):not(.btn) {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
  }
  .defs dd > a[href^="tel:"]:first-child:not(:only-child):not(.btn) {
    margin-top: -0.875rem;
  }
  /* The Privacy notice and Cookie policy links at the foot of a page. */
  .app-main > .caption a {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
  }
  /* The month view's add button: 24px to see, 44px to hit. */
  .cal__plus {
    position: relative;
  }
  .cal__plus::after {
    content: "";
    position: absolute;
    inset: -0.625rem;
  }
}

/* ------------------------------------------------------------ date fields */
/* iOS centres a date's value and lets an empty date field collapse. Keep
   the native control (appearance: none would collapse it further) and
   left-align the value like every other field. */
input[type="date"].field,
input[type="datetime-local"].field,
input[type="time"].field {
  min-width: 0;
}
@media (max-width: 1023px), (pointer: coarse) {
  input[type="date"].field,
  input[type="datetime-local"].field,
  input[type="time"].field { min-height: 3.25rem; }
}
.field::-webkit-date-and-time-value {
  text-align: left;
  min-height: 1.5em;
}

/* ----------------------------------------------------------------- header */
/* 52px on phones and tablets (the polish layer's 68px is for desktop), and
   clear of the rounded corners and sensor housing on a phone on its side. */
@media (max-width: 1023px) {
  body.app .app-header__inner {
    min-height: 3.25rem;
    padding-block: 0.25rem;
  }
}
body.app .app-header__inner {
  padding-left: max(1.25rem, var(--safe-left));
  padding-right: max(1.25rem, var(--safe-right));
}
@media (min-width: 640px) {
  body.app .app-header__inner {
    padding-left: max(2rem, var(--safe-left));
    padding-right: max(2rem, var(--safe-right));
  }
}
/* A phone on its side has little height: the header scrolls away and the
   tab bar stays. */
@media (max-height: 500px) and (pointer: coarse) {
  body.app .app-header {
    position: relative;
  }
}
/* Until auth.js fills the header (after the profile has loaded) it is
   empty; hold its place so the page does not drop under a thumb. Heights
   match .app-header__inner: 4.25rem on desktop, 3.25rem below 1024px. */
body.app > #app-header:empty {
  display: block;
  position: sticky;
  top: 0;
  z-index: 30;
  min-height: calc(4.25rem + 1px + var(--safe-top));
  background: #fff;
  border-bottom: 1px solid var(--line);
}
@media (max-width: 1023px) {
  body.app > #app-header:empty { min-height: calc(3.25rem + 1px + var(--safe-top)); }
}

/* ---------------------------------------------------- tab bar, More sheet */
/* Wider phones and the iPad mini keep the four tabs together in the middle,
   as tablets do. */
@media (max-width: 767px) {
  .tabbar {
    padding-left: max(var(--safe-left), calc((100% - 36rem) / 2));
    padding-right: max(var(--safe-right), calc((100% - 36rem) / 2));
  }
}
/* A drag on the dimmed area or the list must not scroll the page behind. */
.more-sheet {
  justify-content: center;
  overscroll-behavior: contain;
  touch-action: none;
}
.more-sheet__panel {
  max-width: 36rem;
  overscroll-behavior: contain;
  touch-action: pan-y;
}
.more-sheet__panel a.is-active {
  font-weight: 600;
  box-shadow: inset 3px 0 0 var(--gold);
}
/* The same for a dialog: a drag on the dimmed area never scrolls the page;
   a pinch still zooms. The card scrolls (overflow: auto), so it still pans. */
.modal-backdrop {
  touch-action: pinch-zoom;
}
.modal {
  overscroll-behavior: contain;
}
/* A card with nothing to scroll (ui.js sets is-still) refuses the drag too,
   so it cannot reach the page. Fields and lists that scroll keep their own. */
.modal.is-still {
  touch-action: pinch-zoom;
}

/* ------------------------------------------------------------------ lists */
/* .list--links: the title link covers the whole row, so the row is the
   target. Only for rows with no other control in them. */
.list--links > li {
  position: relative;
}
.list--links a.is-strong::after {
  content: "";
  position: absolute;
  inset: 0;
}
.list--links a.is-strong:focus-visible {
  outline: none;
}
.list--links a.is-strong:focus-visible::after {
  outline: 2px solid var(--brand-700);
  outline-offset: -2px;
}
/* .list--actions: rows that end in buttons. The text takes the space; on a
   phone the buttons drop underneath instead of squeezing it. */
.list--actions > li > :first-child {
  flex: 1 1 auto;
  min-width: 0;
}
.list--actions > li > .btn,
.list--actions > li > .row {
  flex: none;
}
.list--actions .row {
  align-items: center;
}
.list--actions .btn,
.panel__head .btn,
.panel__head .btn-link {
  white-space: nowrap;
}
@media (max-width: 767px) {
  .list--actions > li {
    flex-wrap: wrap;
    row-gap: 0.75rem;
  }
  .list--actions > li > :first-child {
    flex-basis: 100%;
  }
  .list--actions > li > .row {
    flex: 1 1 100%;
  }
}
/* A heading and its button or caption share a line while they fit. */
.panel__head {
  flex-wrap: wrap;
  row-gap: 0.5rem;
}

/* ----------------------------------------------------------------- tables */
/* /admin/assessors: two columns give way below 1200px so the actions fit. */
@media (max-width: 1199px) {
  .table--assessors th:nth-child(3),
  .table--assessors td:nth-child(3),
  .table--assessors th:nth-child(4),
  .table--assessors td:nth-child(4) {
    display: none;
  }
}
/* .table--stack: on a phone each row is a card. Who and what on the left,
   the amount on the right, Edit and Remove underneath. */
@media (max-width: 767px) {
  .table--stack,
  .table--stack tbody {
    display: block;
  }
  .table--stack thead {
    display: none;
  }
  .table--stack tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 1rem;
    row-gap: 0.15rem;
    align-items: start;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--line);
  }
  .table--stack tr:last-child {
    border-bottom: 0;
  }
  .table--stack td {
    padding: 0;
    border: 0;
  }
  .table--stack td.ts-who {
    grid-column: 1;
    grid-row: 1;
    font-size: 0.8rem;
    color: var(--ink-faint);
  }
  .table--stack td.ts-what {
    grid-column: 1;
    grid-row: 2;
  }
  .table--stack td.num {
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: center;
    white-space: nowrap;
  }
  .table--stack td.ts-actions {
    grid-column: 1 / -1;
    display: flex;
    gap: 0.5rem;
    margin: 0.25rem 0 -0.75rem;
    text-align: left;
    white-space: normal;
  }
  .table--stack td.ts-actions .btn-link {
    justify-content: flex-start;
  }
  .table--stack tr.ts-total {
    padding-block: 0.75rem;
  }
  .table--stack tr.ts-total td.ts-who {
    font-size: inherit;
    color: var(--ink);
  }
  .table--stack tr.ts-total td.num {
    grid-row: 1;
  }
  .table--stack td:empty {
    display: none;
  }
  .table--stack td.empty {
    grid-column: 1 / -1;
    padding: 1.5rem 0;
    text-align: center;
  }
}

/* ------------------------------------------------------------------ forms */
/* An empty cell that keeps a two-column form aligned has no place in one
   column. */
@media (max-width: 639px) {
  .form-grid__spacer {
    display: none;
  }
}
/* A form that should come before a history list on a narrow screen. */
@media (max-width: 1023px) {
  .grid-main > .order-first-narrow {
    order: -1;
  }
}
/* An error inside a button bar has a row of its own above the buttons, so
   it shows beside the button that was tapped without squeezing it. */
.form-actions > .form-error {
  flex: 1 0 100%;
  margin: 0 0 0.25rem;
}
/* Phone toolbars: a select has a sensible share of the row, so two selects
   sit side by side and the search keeps a row of its own. */
@media (max-width: 767px) {
  .toolbar select.field {
    flex: 1 1 9rem;
    min-width: 0;
  }
}

/* ---------------------------------------------------------- selection bar */
/* On a phone the jobs selection bar holds the count, All or None, Done and
   Delete: tighter gaps and button padding keep Delete inside the rounded
   edge, and the count gives way before a button does. */
@media (max-width: 767px) {
  .selbar {
    gap: 0.5rem;
    padding-left: 1rem;
  }
  .selbar .btn {
    padding-inline: 0.875rem;
  }
  .selbar__count {
    min-width: 0;
  }
}

/* ---------------------------------------------------------- small phones */
/* 375-479px: a little less side padding, and label-over-value details, so
   an email or a certificate number does not break mid-word. */
@media (max-width: 479px) {
  .panel__head {
    padding-inline: 1.25rem;
  }
  .panel__body {
    padding: 1.25rem;
  }
  .panel__body--flush {
    padding: 0;
  }
  .list > li {
    padding-inline: 1.25rem;
  }
  .defs {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 0;
  }
  .defs dt {
    font-size: 0.8rem;
    margin-top: 0.85rem;
  }
  .defs dt:first-child {
    margin-top: 0;
  }
  .defs dd {
    margin-top: 0.1rem;
  }
  /* Dashboard rows: the badge sits above the text instead of beside it. */
  .list--links > li {
    flex-wrap: wrap;
    row-gap: 0.4rem;
  }
  .list--links > li > :first-child {
    flex: 1 1 100%;
    min-width: 0;
  }
  .list--links > li > .badge {
    order: -1;
  }
}
.defs a[href^="tel:"] {
  white-space: nowrap;
}
.page-head h1 .badge {
  vertical-align: middle;
}

/* ------------------------------------------------------ pressed and chosen */
/* Taps show at once (ui.js adds the touchstart listener iOS needs for
   :active). Hover effects are for mouse screens only; see the (hover:
   hover) queries above. */
.tabbar svg {
  transition: transform 0.15s var(--ease);
}
.tabbar a:active,
.tabbar button:active {
  color: var(--brand-700);
}
.tabbar a:active svg,
.tabbar button:active svg {
  transform: scale(0.9);
}
.more-sheet__panel a:active,
.more-sheet__panel button:active,
.card-list a.card-row:active,
.list--links > li:active,
.table tr.is-clickable:active td {
  background: var(--paper);
}
.cal--month .cal__cell:active {
  border-color: var(--line-strong);
}
.btn-link:active {
  opacity: 0.7;
}
/* A ticked row stays red even while the pointer rests on it. */
.is-selecting .table tr.is-selected td {
  background: var(--danger-soft);
}

/* ------------------------------------------------------ keyboard and modal */
/* While the keyboard is up, iOS does not shrink the page, so anything pinned
   to the bottom would sit behind it or jump: the pinned bar goes back into
   the form under the field and the tab bar steps aside. */
body.kb-open .tabbar {
  display: none;
}
body.kb-open .form-actions--sticky {
  position: static;
  margin: 1.25rem 0 0;
  padding: 0;
  background: none;
  border: 0;
  box-shadow: none;
}
/* The jobs selection bar steps back into the page too, under the list. */
@media (max-width: 1023px) {
  body.kb-open .selbar {
    position: static;
    margin: 1rem 0 0;
  }
}
/* The keyboard covers the home indicator, so a dialog pressed against it
   needs no room for it. The sticky offsets still match the padding. */
body.kb-open .modal {
  padding-bottom: 1.25rem;
}
@media (max-width: 1023px), (max-height: 540px), (pointer: coarse) {
  body.kb-open .modal__actions {
    bottom: -1.25rem;
    margin-bottom: -1.25rem;
    padding-bottom: 0.75rem;
  }
}
/* On a touch screen a dialog opens with the card itself focused (so the
   keyboard stays down until a field is tapped); the card needs no ring. */
.modal:focus {
  outline: none;
}
/* Toasts move to the top while the keyboard is up, and above a phone's
   bottom sheet while a dialog is open, so they never cover its buttons. */
body.kb-open .toast-host {
  top: calc(var(--safe-top) + 0.75rem);
  bottom: auto;
}
@media (max-width: 767px) {
  body.modal-open .toast-host {
    top: calc(var(--safe-top) + 0.75rem);
    bottom: auto;
  }
  /* A pinned action bar is showing: the page ends clear of it and toasts
     sit above it rather than over the Save or Send button. */
  body:has(.panel:not([hidden]) .form-actions--sticky) .app-main {
    padding-bottom: calc(var(--tabbar-h) + var(--tabbar-pb) + var(--pinned-h, 4.5rem) + 1.5rem);
  }
  body:not(.kb-open):not(.modal-open):has(.panel:not([hidden]) .form-actions--sticky) .toast-host {
    bottom: calc(var(--tabbar-h) + var(--tabbar-pb) + var(--pinned-h, 4.5rem) + 0.75rem);
  }
}

/* Batch booking (29 September 2026): the arrival window under a job card's time. */
.job-card__window {
  display: block;
  margin-top: 0.15rem;
  font-family: var(--font-sans);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--gold-dark);
}

/* New to assessing (29 September 2026): our other products and the reading list. */
.product-card {
  display: grid;
  gap: 0.4rem;
  margin-top: 1.25rem;
  padding: 1.25rem 1.5rem;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--paper);
  color: var(--ink-soft);
  text-decoration: none;
  transition: border-color 0.2s;
}
@media (hover: hover) and (pointer: fine) {
  .product-card:hover { border-color: var(--gold); }
}
.product-card:active { border-color: var(--gold); }
.product-card__name { font-family: var(--font-display); font-weight: 500; font-size: 1.3rem; color: var(--navy); }
.product-card__text { line-height: 1.6; }
body.app .product-card .link-more {
  margin-top: 0.25rem;
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  font-weight: 600;
  color: var(--navy);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.reading { display: grid; gap: 1.5rem; margin-top: 1.25rem; }
@media (min-width: 760px) { .reading { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.reading__group h3 { font-family: var(--font-sans); font-size: 0.76rem; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: var(--gold-dark); }
.reading__group ul { list-style: none; margin: 0.5rem 0 0; padding: 0; display: grid; gap: 0.25rem; }
.reading__group li { display: grid; padding: 0.35rem 0; border-bottom: 1px solid var(--line); }
.reading__group li:last-child { border-bottom: 0; }
.reading__group a { display: inline-flex; align-items: center; min-height: 2.75rem; font-weight: 600; color: var(--navy); text-underline-offset: 3px; }
.reading__group span { margin-top: -0.35rem; font-size: 0.875rem; line-height: 1.5; color: var(--ink-faint); }

/* Sweep fixes (29 September 2026). */
/* iPad mini and large phones on their side (700-767px): buttons keep their size. */
@media (min-width: 700px) and (max-width: 767px) {
  .page-head__actions .btn, .form-actions .btn, .job-card__actions .btn { flex: 0 0 auto; }
}
/* The diary's intro gives way on the smallest phones so today's row is in view. */
@media (max-width: 479px) { .page-head--diary p { display: none; } }

/* Long words (7 October 2026): an email, a pasted link, a file name or a
   certificate number has no break points, so on a phone it would widen the
   page and let it pan sideways. Each of these wraps inside its own box. */
.list > li > :first-child,
.checkbox > span,
.card-row__top > .card-row__title {
  min-width: 0;
}
.list > li > :first-child,
.checkbox > span,
.card-row__title,
.card-row__line,
.card-row__meta,
.job-card__address,
.job-card__notes,
body.app .help,
body.app .small-copy {
  overflow-wrap: anywhere;
}
/* break-word, not anywhere: tables and rows inside a dialog keep their widths. */
.modal,
.toast {
  overflow-wrap: break-word;
}

/* A long name in the diary's 'Whose diary' select would hold the page head
   wider than a phone. The action row may narrow to the column, and a select
   in it is capped at that width. */
.page-head__actions {
  min-width: 0;
  max-width: 100%;
}
.page-head__actions > select.field {
  max-width: 100%;
  min-width: 0;
}

/* A temporary password to pass on: one tap or long press selects all of it. */
.temp-password {
  padding: 0.75rem 1rem;
  border-radius: var(--radius-lg, 10px);
  background: var(--paper);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 1.15rem;
  letter-spacing: 0.04em;
  color: var(--ink);
  -webkit-user-select: all;
  user-select: all;
  overflow-wrap: anywhere;
}

/* Assessor pages are used outdoors on a phone: help under a field is a
   size up and darker, and the line that says what the certificate file
   check found (or why it refused) is larger again, error or not. */
body.app--assessor .help {
  font-size: 0.875rem;
  color: var(--ink-soft);
}
body.app--assessor .help.field-msg {
  color: var(--danger);
}
body.app--assessor #xml-note,
body.app--assessor #late-xml-note {
  font-size: 0.9375rem;
}
