/* ============================================================================
   ULTRABASIC LABS — portal layer
   Loaded AFTER site.css, on /admin/ and /portal/ only. Never on the marketing
   site.

   site.css is a marketing stylesheet: it has no table, no sidebar, no tabs, no
   modal, no toast, no badge, no boxed input, no checkbox, no empty state, no
   pagination — and no semantic colour whatsoever. This file adds exactly those
   things and nothing else, composing from site.css tokens so the two read as
   one product.

   House rules inherited from site.css and kept here:
     · flat and hairline-separated — a rule, not a box; a box, not a shadow
     · shadows only on floating chrome (modal, drawer, menu, toast)
     · 11px / 700 / .07em uppercase for micro-labels
     · weight does the work, not colour
     · every interactive element keeps the global :focus-visible ring

   Naming: everything is prefixed `p-` so it can never collide with a marketing
   component. State classes follow the site's `is-*` convention.
   ========================================================================= */

:root {
  /* ---- SEMANTIC STATUS -----------------------------------------------
     Tuned against the existing pastels (--mint, --butter, --ice, --blush)
     rather than lifted from a generic UI kit, so a status pill sits inside
     the Pink dawn system instead of beside it. Each pair is a soft surface
     plus a text tone that clears 4.5:1 on it. Status only — these are not
     general-purpose colours. */
  --ok:      #1f7a4d;  --ok-soft:      #d8f4df;
  --warn:    #8a6300;  --warn-soft:    #fdf0c0;
  --danger:  #a32020;  --danger-soft:  #ffe0dc;
  --info:    #1f5f88;  --info-soft:    #d2f4ff;
  --busy:    #8a3d78;  --busy-soft:    #f7e1f7;
  --muted:   #5c5c5c;  --muted-soft:   #f1f1f1;

  /* Washes: the same hues at the far end of the scale, for surfaces that must
     tint without competing with the page. The -soft tokens stay for badges,
     where a small pill needs the saturation to register at all. */
  --ok-wash:     #f4faf6;
  --warn-wash:   #fdfaef;
  --danger-wash: #fdf6f5;
  --info-wash:   #f4fafd;

  --rail-w: 244px;
  --topbar-h: 68px;
  --p-r: 4px;              /* the portal's default radius — matches --r-card */
  --shadow-float: 0 18px 48px rgba(0, 0, 0, .13), 0 2px 6px rgba(0, 0, 0, .05);
}

/* ============================================================ app frame == */
body.p-app {
  background: var(--canvas);
  min-height: 100vh;
  min-height: 100dvh;
}

.p-shell {
  display: grid;
  grid-template-columns: var(--rail-w) minmax(0, 1fr);
  min-height: 100vh;
  min-height: 100dvh;
}

/* ---------------------------------------------------------------- rail -- */
.p-rail {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  border-right: 1px solid var(--hairline);
  background: var(--cream);
  padding: 0 0 14px;
}

/* This block is the rail's half of the topbar, so it owns that height outright
   rather than arriving near it through padding: the two hairlines have to meet
   across the corner, and a stack of paddings nothing keeps in step will not.
   Stacked rather than inline because the pill holds a company name, and beside
   a 108px wordmark in a 244px rail there is room for about nine characters. */
.p-rail-brand {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 7px;
  height: var(--topbar-h);
  padding: 0 22px;
  margin-bottom: 6px;
  border-bottom: 1px solid var(--hairline);
}
.p-rail-brand > a { flex: none; display: block; }
.p-rail-brand .logo { width: 108px; height: auto; color: var(--ink); }
/* The client portal puts the company name in here, so it has to survive a long
   one: never wrap the pill, shrink and ellipsis instead. */
.p-rail-tag {
  min-width: 0;
  max-width: 100%;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--fog);
  border: 1px solid var(--hairline);
  border-radius: var(--r-pill);
  padding: 3px 8px;
  background: var(--canvas);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---- the palette's handle in the rail ---------------------------------
   A button rather than a real field: the palette is a dialog, and a field
   here that is not the field you end up typing into is a small lie. It
   carries the shortcut so the shortcut gets discovered. */
.p-railsearch {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 12px 12px 2px;
  padding: 9px 10px 9px 11px;
  border: 1px solid var(--hairline);
  border-radius: var(--p-r);
  background: var(--canvas);
  font-size: 13.5px;
  color: var(--fog);
  transition: border-color .18s var(--ease), color .18s var(--ease);
}
.p-railsearch:hover { border-color: var(--mist); color: var(--charcoal); }
.p-railsearch svg { width: 15px; height: 15px; flex: none; }
.p-railsearch span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.p-railsearch-key {
  margin-left: auto;
  flex: none;
  font-family: inherit;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--fog);
  border: 1px solid var(--hairline);
  border-radius: var(--p-r);
  padding: 2px 5px;
  background: var(--cream);
}

.p-rail-nav {
  flex: 1;
  overflow-y: auto;
  padding: 14px 12px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* ---- the rail's folding groups ----------------------------------------
   The pinned block sits above them and never folds: Dashboard, Inbox and
   Messages are where the day starts, and a fold in front of them buys
   nothing. Below that each group is a disclosure, opened by the router when
   you are inside it and remembered when you open one by hand. */
.p-rail-pinned { display: flex; flex-direction: column; gap: 2px; }
.p-rail-pinned + .p-railgroup { margin-top: 10px; }

.p-railgroup + .p-railgroup { margin-top: 2px; }
.p-railgroup-head {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 9px 10px 9px 12px;
  border-radius: var(--p-r);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--fog);
  transition: background .18s var(--ease), color .18s var(--ease);
}
.p-railgroup-head:hover { background: var(--canvas); color: var(--charcoal); }
.p-railgroup-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.p-railgroup-head svg {
  width: 13px;
  height: 13px;
  margin-left: auto;
  opacity: .5;
  transition: transform .22s var(--ease);
}
.p-railgroup.is-open > .p-railgroup-head svg { transform: rotate(180deg); }

/* A shut group must not swallow an unread badge, so the header wears a dot
   while one of its links is carrying a count. */
.p-railgroup-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--bubblegum-deep);
  flex: none;
}
.p-railgroup.is-open .p-railgroup-dot { display: none; }

.p-railgroup-items {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 2px 0 6px;
}
.p-railgroup-items[hidden] { display: none; }

.p-nav {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 10px 12px;
  border-radius: var(--p-r);
  font-size: 14px;
  font-weight: 500;
  color: var(--charcoal);
  transition: background .18s var(--ease), color .18s var(--ease);
}
.p-nav svg { width: 17px; height: 17px; flex: none; opacity: .62; }
.p-nav:hover { background: var(--canvas); color: var(--ink); }
.p-nav.is-active { background: var(--ink); color: #fff; }
.p-nav.is-active svg { opacity: 1; }
.p-nav-count {
  margin-left: auto;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: var(--r-pill);
  background: var(--cotton);
  color: var(--ink);
  font-size: 11px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-variant-numeric: tabular-nums;
}
.p-nav.is-active .p-nav-count { background: var(--bubblegum); }
.p-nav-count:empty, .p-nav-count[hidden] { display: none; }

.p-rail-foot { padding: 12px 12px 0; border-top: 1px solid var(--hairline); }

/* the signed-in user, bottom of the rail */
.p-who {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 10px;
  border-radius: var(--p-r);
  text-align: left;
  transition: background .18s var(--ease);
}
.p-who:hover { background: var(--canvas); }
.p-who-text { min-width: 0; flex: 1; }
.p-who-name {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.p-who-sub {
  display: block;
  font-size: 11px;
  color: var(--fog);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---------------------------------------------------------------- main -- */
.p-main { min-width: 0; display: flex; flex-direction: column; }

.p-topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: var(--topbar-h);
  padding: 0 clamp(20px, 3vw, 40px);
  background: rgba(255, 255, 255, .88);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid var(--hairline);
}
.p-topbar-title {
  font-family: var(--font-head);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -.012em;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.p-topbar-actions { margin-left: auto; display: flex; align-items: center; gap: 10px; }

.p-view { padding: clamp(22px, 3vw, 38px) clamp(20px, 3vw, 40px) 96px; flex: 1; }
.p-view--narrow { max-width: 860px; }
.p-view--reading { max-width: 720px; }

/* mobile rail toggle — hidden on desktop */
.p-railtoggle { display: none; width: 22px; height: 16px; position: relative; flex: none; }
.p-railtoggle span {
  position: absolute; left: 0; right: 0; height: 1.5px; background: var(--ink);
  transition: transform .3s var(--ease), opacity .2s var(--ease);
}
.p-railtoggle span:nth-child(1) { top: 0; }
.p-railtoggle span:nth-child(2) { top: 7px; }
.p-railtoggle span:nth-child(3) { top: 14px; }
.p-scrim { display: none; }

/* ========================================================== page furniture */
.p-head { margin-bottom: 26px; }
.p-head-row { display: flex; align-items: flex-start; gap: 20px; flex-wrap: wrap; }
.p-head-row > .p-head-actions { margin-left: auto; display: flex; gap: 10px; flex-wrap: wrap; }
.p-title {
  font-family: var(--font-title);
  font-size: clamp(24px, 2.4vw, 32px);
  line-height: 1.2;
  letter-spacing: -.006em;
  font-weight: 300;
}
.p-sub { margin-top: 8px; font-size: 14.5px; color: var(--charcoal); max-width: 62ch; }

.p-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--fog);
}

.p-section { margin-top: 40px; }
.p-section-head {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding-bottom: 12px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--hairline);
}
.p-section-head h2 {
  font-family: var(--font-head);
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -.008em;
}
.p-section-head .p-section-more { margin-left: auto; }

.p-grid { display: grid; gap: 16px; }
.p-grid--2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.p-grid--3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.p-grid--4 { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.p-grid--split { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: 28px; }

/* ----------------------------------------------------------------- card -- */
.p-card {
  border: 1px solid var(--hairline);
  border-radius: var(--r-panel);
  background: var(--canvas);
  padding: 20px 22px;
  min-width: 0;
}
/* A whole-card link with other controls in it. The anchor stretches over the
   card with ::after rather than wrapping it, because an <a> containing a
   <button> is invalid and leaves the button unreachable by keyboard in some
   browsers. Everything interactive sits above the stretched layer. */
.p-card--link { position: relative; }
.p-card--link:hover { border-color: var(--mist); }
.p-card-target::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}
.p-card--link :is(button, a:not(.p-card-target), input, label) {
  position: relative;
  z-index: 1;
}
.p-card--link:focus-within { border-color: var(--ink); }

.p-card--cream { background: var(--cream); }
.p-card--flush { padding: 0; overflow: hidden; }
.p-card-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 22px;
  border-bottom: 1px solid var(--hairline);
}
.p-card-head h3 { font-size: 14px; font-weight: 700; letter-spacing: -.005em; }
.p-card-head .p-card-more { margin-left: auto; }
.p-card-body { padding: 20px 22px; }
.p-card-foot {
  padding: 14px 22px;
  border-top: 1px solid var(--hairline);
  background: var(--cream);
  display: flex;
  align-items: center;
  gap: 10px;
}

/* KPI tile */
.p-stat {
  border: 1px solid var(--hairline);
  border-radius: var(--r-panel);
  padding: 18px 20px 20px;
  background: var(--canvas);
  min-width: 0;
}
.p-stat-cap {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--fog);
}
.p-stat-num {
  display: block;
  margin-top: 10px;
  font-family: var(--font-head);
  font-size: clamp(26px, 2.6vw, 34px);
  line-height: 1;
  font-weight: 700;
  letter-spacing: -.022em;
  font-variant-numeric: tabular-nums;
}
.p-stat-meta { margin-top: 8px; font-size: 12.5px; color: var(--fog); }
.p-stat-meta b { font-weight: 600; color: var(--charcoal); }

/* ---- the dashboard's top row -------------------------------------------
   Four equal boxes gave a system status the same weight as the money, and
   put "owed" beside "overdue" as peers — so when the only unpaid invoice was
   also the overdue one, the row showed the same number twice and read as a
   bug. Overdue is a PART of what is owed, so it is drawn as one: a hero card
   with a split bar, and the parts named underneath. */
.p-statrow {
  display: grid;
  gap: 16px;
  grid-template-columns: 1.7fr 1fr 1fr;
  align-items: stretch;
}
@media (max-width: 1080px) { .p-statrow { grid-template-columns: 1fr 1fr; } }
@media (max-width: 640px)  { .p-statrow { grid-template-columns: 1fr; } }

.p-stat--hero { display: flex; flex-direction: column; }
.p-stat--hero .p-stat-num { font-size: clamp(32px, 4vw, 48px); }
/* The supporting numbers step back deliberately. They often carry more digits
   than the hero, and at equal size more digits simply reads as louder. */
.p-statrow .p-stat:not(.p-stat--hero) .p-stat-num { font-size: clamp(22px, 2.2vw, 28px); }

/* The proportion bar. Two segments on one track, so the eye reads the split
   before it reads either number. */
.p-stat-bar {
  display: flex;
  height: 6px;
  border-radius: var(--r-pill);
  overflow: hidden;
  background: var(--hairline);
  margin-top: 18px;
}
.p-stat-bar > i { display: block; height: 100%; }
.p-stat-bar > .is-late    { background: var(--danger); }
.p-stat-bar > .is-current { background: var(--ink); }

.p-stat-split { display: flex; flex-wrap: wrap; gap: 18px; margin-top: 12px; }
.p-stat-split > div { display: flex; align-items: baseline; gap: 7px; font-size: 12.5px; }
.p-stat-split b { font-size: 14px; font-weight: 600; font-variant-numeric: tabular-nums; }
.p-stat-split .p-key {
  width: 7px; height: 7px; border-radius: 50%; flex: none; align-self: center;
}
.p-stat-split .p-key--late    { background: var(--danger); }
.p-stat-split .p-key--current { background: var(--ink); }
.p-stat-split .is-late b { color: var(--danger); }

.p-stat-foot { margin-top: auto; padding-top: 16px; }

/* System health is not a business number, so it sits by the page title as a
   pill rather than occupying a quarter of the row. */
.p-health {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 4px 11px 4px 9px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-pill);
  font-size: 12px;
  font-weight: 500;
  color: var(--charcoal);
  background: var(--canvas);
  white-space: nowrap;
}
.p-health-dot {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: var(--fog);
}
.p-health.is-live  .p-health-dot { background: var(--ok); }
.p-health.is-queue .p-health-dot { background: var(--warn); }
.p-health.is-down  .p-health-dot { background: var(--danger); }

/* key/value rows — the detail-panel workhorse */
.p-kv { display: flex; flex-direction: column; }
.p-kv > div {
  display: flex;
  gap: 18px;
  align-items: baseline;
  padding: 11px 0;
  border-bottom: 1px solid var(--hairline);
  font-size: 14px;
}
.p-kv > div:last-child { border-bottom: 0; }
.p-kv dt { color: var(--fog); font-weight: 600; flex: none; min-width: 132px; }
.p-kv dd { font-weight: 500; margin-left: auto; text-align: right; min-width: 0; }
.p-kv dd.num { font-variant-numeric: tabular-nums; }

/* =============================================================== table === */
.p-tablewrap {
  border: 1px solid var(--hairline);
  border-radius: var(--r-panel);
  overflow-x: auto;
  background: var(--canvas);
}
.p-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.p-table th {
  position: sticky;
  top: 0;
  z-index: 1;
  text-align: left;
  padding: 12px 16px;
  background: var(--cream);
  border-bottom: 1px solid var(--hairline);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--fog);
  white-space: nowrap;
}
.p-table td {
  padding: 14px 16px;
  border-bottom: 1px solid var(--hairline);
  vertical-align: middle;
}
.p-table tbody tr:last-child td { border-bottom: 0; }
.p-table .num, .p-table th.num { text-align: right; font-variant-numeric: tabular-nums; }
.p-table .p-t-strong { font-weight: 600; color: var(--ink); }
.p-table .p-t-sub { display: block; font-size: 12.5px; color: var(--fog); margin-top: 2px; }
.p-table .p-t-actions { text-align: right; white-space: nowrap; }

/* a whole row that navigates — mirrors .svcrow's hover wash */
.p-table tbody tr.is-link { cursor: pointer; transition: background .16s var(--ease); }
.p-table tbody tr.is-link:hover { background: var(--wash, var(--cream)); }
.p-table tbody tr.is-link:focus-visible { outline: 2px solid var(--ink); outline-offset: -2px; }

/* sortable header */
.p-th-sort { display: inline-flex; align-items: center; gap: 6px; color: inherit; font: inherit; }
.p-th-sort svg { width: 11px; height: 11px; opacity: 0; transition: opacity .18s var(--ease), transform .18s var(--ease); }
.p-th-sort:hover svg { opacity: .5; }
.p-th-sort.is-asc svg, .p-th-sort.is-desc svg { opacity: 1; }
.p-th-sort.is-desc svg { transform: rotate(180deg); }

.p-table--compact td { padding: 9px 14px; }
.p-table--compact th { padding: 9px 14px; }

/* ============================================================== badges === */
.p-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: var(--r-pill);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .02em;
  white-space: nowrap;
  background: var(--muted-soft);
  color: var(--muted);
}
.p-badge::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}
.p-badge--plain::before { display: none; }
.p-badge--ok      { background: var(--ok-soft);     color: var(--ok); }
.p-badge--warn    { background: var(--warn-soft);   color: var(--warn); }
.p-badge--danger  { background: var(--danger-soft); color: var(--danger); }
.p-badge--info    { background: var(--info-soft);   color: var(--info); }
.p-badge--busy    { background: var(--busy-soft);   color: var(--busy); }
.p-badge--draft   { background: transparent; color: var(--fog); box-shadow: inset 0 0 0 1px var(--hairline); }

/* ============================================================== forms ==== */
/* site.css only has bottom-ruled fields (.cf-input), which are right for a
   contact form and wrong for a dense one. These are the boxed counterparts. */
.p-field { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.p-field-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--fog);
  transition: color .2s var(--ease);
}
.p-field:focus-within .p-field-label { color: var(--ink); }
.p-field-req { color: var(--bubblegum-deep); }

.p-input, .p-select, .p-textarea {
  font: inherit;
  font-size: 14.5px;
  width: 100%;
  color: var(--ink);
  background: var(--canvas);
  border: 1px solid var(--mist);
  border-radius: var(--p-r);
  padding: 11px 13px;
  transition: border-color .2s var(--ease), background .2s var(--ease);
}
.p-textarea { resize: vertical; min-height: 96px; line-height: 1.55; }
.p-input::placeholder, .p-textarea::placeholder { color: var(--mist); }
.p-input:focus, .p-select:focus, .p-textarea:focus {
  outline: none;
  border-color: var(--ink);
}
.p-input:disabled, .p-select:disabled, .p-textarea:disabled {
  background: var(--neutral-soft, #f1f1f1);
  color: var(--fog);
  cursor: not-allowed;
}
.p-input.is-error, .p-select.is-error, .p-textarea.is-error { border-color: var(--danger); }

.p-select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 36px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M4 6.5L8 10.5L12 6.5' stroke='%23333' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 11px center;
  background-size: 16px;
}

.p-field-hint  { font-size: 12.5px; color: var(--fog); }
.p-field-error { font-size: 12.5px; color: var(--danger); font-weight: 500; }
.p-field-error:empty, .p-field-hint:empty { display: none; }

/* prefix/suffix, e.g. a currency symbol glued to an amount */
.p-inputgroup {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--mist);
  border-radius: var(--p-r);
  overflow: hidden;
  background: var(--canvas);
  transition: border-color .2s var(--ease);
}
.p-inputgroup:focus-within { border-color: var(--ink); }
.p-inputgroup .p-input { border: 0; border-radius: 0; }
.p-inputgroup .p-input:focus { outline: none; }
.p-inputgroup-fix {
  display: inline-flex;
  align-items: center;
  padding: 0 12px;
  background: var(--cream);
  border-right: 1px solid var(--hairline);
  color: var(--fog);
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
}
.p-inputgroup-fix--end { border-right: 0; border-left: 1px solid var(--hairline); }

/* search field with a leading glyph */
.p-search { position: relative; min-width: 0; }
.p-search svg {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  width: 15px;
  height: 15px;
  color: var(--fog);
  pointer-events: none;
}
.p-search .p-input { padding-left: 35px; border-radius: var(--r-pill); }

/* checkbox / radio / switch — none of these existed */
.p-check, .p-radio {
  display: inline-flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 14px;
  cursor: pointer;
  line-height: 1.4;
}
.p-check input, .p-radio input {
  appearance: none;
  -webkit-appearance: none;
  width: 17px;
  height: 17px;
  flex: none;
  margin: 1px 0 0;
  border: 1px solid var(--mist);
  background: var(--canvas);
  cursor: pointer;
  transition: background .16s var(--ease), border-color .16s var(--ease);
}
.p-check input { border-radius: var(--p-r); }
.p-radio input { border-radius: 50%; }
.p-check input:checked, .p-radio input:checked { background: var(--ink); border-color: var(--ink); }
.p-check input:checked {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M3.5 8.5L6.5 11.5L12.5 5' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-size: 13px;
  background-position: center;
  background-repeat: no-repeat;
}
.p-radio input:checked { box-shadow: inset 0 0 0 3.5px var(--canvas); }
.p-check input:disabled, .p-radio input:disabled { opacity: .45; cursor: not-allowed; }

.p-switch { display: inline-flex; align-items: center; gap: 11px; cursor: pointer; font-size: 14px; }
.p-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.p-switch-track {
  width: 38px;
  height: 22px;
  flex: none;
  border-radius: var(--r-pill);
  background: var(--mist);
  position: relative;
  transition: background .2s var(--ease);
}
.p-switch-track::after {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  transition: transform .22s var(--ease);
}
.p-switch input:checked + .p-switch-track { background: var(--ink); }
.p-switch input:checked + .p-switch-track::after { transform: translateX(16px); }
.p-switch input:focus-visible + .p-switch-track { outline: 2px solid var(--ink); outline-offset: 3px; }

/* file dropzone */
.p-drop {
  border: 1.5px dashed var(--mist);
  border-radius: var(--r-panel);
  padding: 30px 24px;
  text-align: center;
  color: var(--fog);
  font-size: 14px;
  transition: border-color .2s var(--ease), background .2s var(--ease), color .2s var(--ease);
  cursor: pointer;
}
.p-drop:hover, .p-drop.is-over { border-color: var(--ink); background: var(--cream); color: var(--ink); }
.p-drop b { display: block; color: var(--ink); font-weight: 600; margin-bottom: 4px; }
.p-drop input[type="file"] { position: absolute; width: 1px; height: 1px; opacity: 0; }

.p-form { display: flex; flex-direction: column; gap: 18px; }
.p-formrow { display: grid; gap: 18px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.p-formfoot {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-top: 6px;
  flex-wrap: wrap;
}
.p-formfoot .p-spacer { margin-left: auto; }

/* =========================================================== feedback ==== */
/* A banner is a note with a flag on it, not a coloured slab. The pastel fills
   this used to carry read louder than the page they sat on: two stacked made a
   traffic light, and setting the whole sentence in the semantic colour meant
   the urgent half and the incidental half shouted equally.

   So: near-white wash, hairline all round, the semantic colour spent on a 3px
   edge and the opening clause only. Weight does the work — the house rule the
   filled version was quietly breaking. */
.p-banner {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 13px 16px 13px 15px;
  border: 1px solid var(--hairline);
  border-left: 3px solid var(--mist);
  border-radius: var(--p-r);
  font-size: 14px;
  line-height: 1.6;
  background: var(--canvas);
  color: var(--charcoal);
}
/* An unbounded banner sets a 160-character line on a wide screen, which is
   about twice what anyone reads comfortably. */
.p-banner > div { max-width: 82ch; min-width: 0; }
.p-banner b { color: var(--ink); font-weight: 600; }

.p-banner--ok     { background: var(--ok-wash);     border-left-color: var(--ok); }
.p-banner--warn   { background: var(--warn-wash);   border-left-color: var(--warn); }
.p-banner--danger { background: var(--danger-wash); border-left-color: var(--danger); }
.p-banner--info   { background: var(--info-wash);   border-left-color: var(--info); }
.p-banner--ok b     { color: #14532d; }
.p-banner--warn b   { color: #5c4200; }
.p-banner--danger b { color: #7a1717; }
.p-banner--info b   { color: #14405c; }

/* For a caveat rather than an alert — "this is issued, editing changes what
   they hold". True, worth saying, not worth a colour. */
/* Quiet means smaller and uncoloured, NOT fainter: --fog on cream measures
   3.28:1, which fails 4.5:1 and would have shipped a note nobody with less than
   perfect sight could read. Size and the absent accent carry the demotion. */
.p-banner--quiet {
  background: var(--cream);
  border-left-color: var(--mist);
  color: var(--charcoal);
  font-size: 13.5px;
}
.p-banner--quiet b { color: var(--charcoal); }
.p-banner-close { margin-left: auto; flex: none; color: inherit; opacity: .6; }
.p-banner-close:hover { opacity: 1; }

.p-toasts {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 120;
  display: flex;
  flex-direction: column;
  gap: 10px;
  pointer-events: none;
  max-width: min(380px, calc(100vw - 40px));
}
.p-toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: 11px;
  padding: 14px 16px;
  border-radius: var(--r-panel);
  background: var(--deep);
  color: #fff;
  font-size: 14px;
  line-height: 1.45;
  box-shadow: var(--shadow-float);
  opacity: 0;
  transform: translateY(10px) scale(.98);
  transition: opacity .26s var(--ease), transform .26s var(--ease);
}
.p-toast.is-in { opacity: 1; transform: none; }
.p-toast::before {
  content: '';
  width: 7px; height: 7px;
  border-radius: 50%;
  margin-top: 6px;
  flex: none;
  background: var(--mist);
}
.p-toast--ok::before     { background: #58d69a; }
.p-toast--danger::before { background: #ff8f8f; }
.p-toast--warn::before   { background: var(--butter); }
.p-toast-close { margin-left: auto; color: #fff; opacity: .55; flex: none; }
.p-toast-close:hover { opacity: 1; }

/* empty state — generalised from the site's .player--slot placeholder */
.p-empty {
  border: 1.5px dashed var(--mist);
  border-radius: var(--r-panel);
  padding: 46px 28px;
  text-align: center;
}
.p-empty-mark {
  /* The same move the marketing site's icons made: the tinted disc goes, the
     glyph grows into the space it was holding, and the colour moves into the
     line. An empty state is mostly air, so a bare icon suits it better than a
     badge floating in the middle of a dashed box. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  margin-bottom: 16px;
  color: var(--cotton-ink);
}
/* Portal glyphs are drawn at 1.7 on a 24 unit grid, which renders at two and a
   half pixels once the box is 36. This holds the line where it was. */
.p-empty-mark svg { width: 36px; height: 36px; stroke-width: 1.15; }
.p-empty h3 {
  font-family: var(--font-title);
  font-size: 18px;
  font-weight: 300;
  letter-spacing: -.004em;
  margin-bottom: 8px;
}
.p-empty p { font-size: 14px; color: var(--fog); max-width: 44ch; margin: 0 auto; }
.p-empty .btn { margin-top: 20px; }

/* skeleton + spinner */
.p-skel {
  border-radius: var(--p-r);
  background: linear-gradient(90deg, #f0f0f0 25%, #f7f7f7 37%, #f0f0f0 63%);
  background-size: 400% 100%;
  animation: pskel 1.3s ease-in-out infinite;
  height: 14px;
}
.p-skel + .p-skel { margin-top: 10px; }
.p-skel--line-sm { width: 40%; }
.p-skel--line-md { width: 70%; }
.p-skel--row { height: 46px; }
@keyframes pskel { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

.p-spin {
  width: 15px; height: 15px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  display: inline-block;
  animation: pspin .7s linear infinite;
  vertical-align: -2px;
}
@keyframes pspin { to { transform: rotate(360deg); } }
.btn[aria-busy="true"] { pointer-events: none; opacity: .7; }

/* progress */
.p-progress { height: 5px; border-radius: var(--r-pill); background: var(--hairline); overflow: hidden; }
.p-progress > i {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--ink);
  transition: width .5s var(--ease);
}
.p-progress--ok > i { background: var(--ok); }

/* ========================================================= overlays ====== */
.p-scrimlayer {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(0, 0, 0, .34);
  opacity: 0;
  transition: opacity .24s var(--ease);
}
.p-scrimlayer.is-in { opacity: 1; }

/* ---- the search palette ------------------------------------------------
   Sits higher than a modal on purpose. A dialog you opened to finish a task
   belongs in the middle of the screen; a dialog you opened to leave the
   screen belongs near the top, where a browser's own address bar is, so the
   results have room to run and the page stays partly visible behind. */
.p-palette {
  position: fixed;
  z-index: 101;
  left: 50%;
  top: 11vh;
  transform: translate(-50%, -8px);
  width: min(620px, calc(100vw - 28px));
  max-height: min(70vh, 620px);
  display: flex;
  flex-direction: column;
  background: var(--canvas);
  border-radius: var(--r-panel);
  box-shadow: var(--shadow-float);
  opacity: 0;
  overflow: hidden;
  transition: opacity .2s var(--ease), transform .2s var(--ease);
}
.p-palette.is-in { opacity: 1; transform: translate(-50%, 0); }

.p-palette-field {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 0 14px;
  height: 56px;
  flex: none;
  border-bottom: 1px solid var(--hairline);
}
.p-palette-field > svg { width: 17px; height: 17px; flex: none; color: var(--fog); }
.p-palette-input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: 16px;   /* 16 keeps iOS from zooming the page on focus */
  color: var(--ink);
  outline: none;
}
.p-palette-input::placeholder { color: var(--mist); }
.p-palette-esc {
  flex: none;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--fog);
  border: 1px solid var(--hairline);
  border-radius: var(--p-r);
  padding: 3px 6px;
  background: var(--cream);
}

.p-palette-results { overflow-y: auto; padding: 6px; flex: 1; }
.p-palette-group + .p-palette-group { margin-top: 4px; }
.p-palette-kind {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--fog);
  padding: 10px 10px 6px;
}
.p-palette-row {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  padding: 9px 10px;
  border-radius: var(--p-r);
  text-align: left;
  color: var(--ink);
}
/* One highlight, driven by the arrow keys, and hover moves it rather than
   adding a second. Two lit rows in a keyboard list is a bug you feel before
   you see it. */
.p-palette-row.is-on { background: var(--cream); }
.p-palette-row.is-on .p-palette-ico { background: var(--cotton); }
.p-palette-ico {
  width: 28px;
  height: 28px;
  flex: none;
  border-radius: var(--p-r);
  background: var(--cream);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--charcoal);
  transition: background .16s var(--ease);
}
.p-palette-ico svg { width: 14px; height: 14px; }
.p-palette-text { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 1px; }
.p-palette-title {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -.006em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.p-palette-sub {
  font-size: 12px;
  color: var(--fog);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.p-palette-meta {
  flex: none;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--fog);
}
.p-palette-note { padding: 22px 12px; text-align: center; font-size: 13.5px; color: var(--fog); }

.p-palette-foot {
  flex: none;
  display: flex;
  gap: 18px;
  padding: 9px 14px;
  border-top: 1px solid var(--hairline);
  background: var(--cream);
  font-size: 11.5px;
  color: var(--fog);
}
.p-palette-foot kbd {
  font-family: inherit;
  font-size: 10.5px;
  border: 1px solid var(--hairline);
  border-radius: var(--p-r);
  padding: 1px 4px;
  margin-right: 3px;
  background: var(--canvas);
}
@media (max-width: 560px) {
  .p-palette { top: 0; width: 100vw; max-height: 100dvh; height: 100dvh; border-radius: 0; }
  .p-palette-foot { display: none; }
}

.p-modal {
  position: fixed;
  z-index: 101;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -46%) scale(.985);
  width: min(560px, calc(100vw - 32px));
  max-height: min(84vh, 760px);
  display: flex;
  flex-direction: column;
  background: var(--canvas);
  border-radius: var(--r-panel);
  box-shadow: var(--shadow-float);
  opacity: 0;
  transition: opacity .24s var(--ease), transform .24s var(--ease);
}
.p-modal.is-in { opacity: 1; transform: translate(-50%, -50%); }
.p-modal--wide { width: min(860px, calc(100vw - 32px)); }

.p-drawer {
  position: fixed;
  z-index: 101;
  top: 0;
  right: 0;
  height: 100vh;
  height: 100dvh;
  width: min(520px, 100vw);
  display: flex;
  flex-direction: column;
  background: var(--canvas);
  border-left: 1px solid var(--hairline);
  box-shadow: var(--shadow-float);
  transform: translateX(100%);
  transition: transform .3s var(--ease);
}
.p-drawer.is-in { transform: none; }

.p-modal-head, .p-drawer-head {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 20px 24px;
  border-bottom: 1px solid var(--hairline);
  flex: none;
}
.p-modal-head h2, .p-drawer-head h2 {
  font-family: var(--font-head);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -.012em;
  min-width: 0;
}
.p-x {
  margin-left: auto;
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--charcoal);
  transition: background .18s var(--ease), color .18s var(--ease);
}
.p-x:hover { background: var(--cream); color: var(--ink); }
.p-x svg { width: 15px; height: 15px; }

.p-modal-body, .p-drawer-body { padding: 22px 24px; overflow-y: auto; flex: 1; }
.p-modal-foot, .p-drawer-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 16px 24px;
  border-top: 1px solid var(--hairline);
  background: var(--cream);
  flex: none;
  flex-wrap: wrap;
}
.p-modal-foot .p-spacer, .p-drawer-foot .p-spacer { margin-left: auto; }

/* light dropdown — the site's .slotmenu is dark and built for the black panel */
.p-menu {
  position: absolute;
  z-index: 60;
  min-width: 190px;
  padding: 6px;
  background: var(--canvas);
  border: 1px solid var(--hairline);
  border-radius: var(--r-panel);
  box-shadow: var(--shadow-float);
}
.p-menu[hidden] { display: none; }
.p-menu button, .p-menu a {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 11px;
  border-radius: var(--p-r);
  font-size: 14px;
  text-align: left;
  color: var(--charcoal);
  transition: background .15s var(--ease), color .15s var(--ease);
}
.p-menu button:hover, .p-menu a:hover { background: var(--cream); color: var(--ink); }
.p-menu svg { width: 15px; height: 15px; opacity: .6; flex: none; }
.p-menu hr { border: 0; border-top: 1px solid var(--hairline); margin: 6px 2px; }
.p-menu .is-danger { color: var(--danger); }
.p-menu .is-danger:hover { background: var(--danger-soft); }

/* ============================================================ navigation = */
.p-tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--hairline);
  overflow-x: auto;
  scrollbar-width: none;
}
.p-tabs::-webkit-scrollbar { display: none; }
.p-tab {
  position: relative;
  padding: 12px 14px;
  font-size: 14px;
  font-weight: 500;
  color: var(--fog);
  white-space: nowrap;
  transition: color .18s var(--ease);
}
.p-tab:hover { color: var(--charcoal); }
.p-tab.is-active { color: var(--ink); font-weight: 600; }
.p-tab::after {
  content: '';
  position: absolute;
  left: 14px;
  right: 14px;
  bottom: -1px;
  height: 2px;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .28s var(--ease);
}
.p-tab.is-active::after { transform: scaleX(1); }
.p-tab-count { margin-left: 7px; font-size: 12px; color: var(--fog); font-variant-numeric: tabular-nums; }

.p-crumbs { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--fog); margin-bottom: 14px; flex-wrap: wrap; }
.p-crumbs a { color: var(--fog); transition: color .18s var(--ease); }
.p-crumbs a:hover { color: var(--ink); }
.p-crumbs svg { width: 12px; height: 12px; opacity: .5; }

/* filter chips over a table */
.p-filters { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; }
.p-chip {
  padding: 7px 14px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-pill);
  font-size: 13px;
  font-weight: 500;
  color: var(--charcoal);
  background: var(--canvas);
  transition: background .18s var(--ease), border-color .18s var(--ease), color .18s var(--ease);
  white-space: nowrap;
}
.p-chip:hover { border-color: var(--mist); background: var(--cream); }
.p-chip.is-active { background: var(--ink); border-color: var(--ink); color: #fff; }
.p-chip-n { opacity: .55; margin-left: 5px; font-variant-numeric: tabular-nums; }

.p-pager {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 18px;
  font-size: 13px;
  color: var(--fog);
}
.p-pager-btns { margin-left: auto; display: flex; gap: 6px; }
.p-pager-btn {
  width: 32px;
  height: 32px;
  border: 1px solid var(--hairline);
  border-radius: var(--p-r);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--charcoal);
  transition: background .16s var(--ease), border-color .16s var(--ease);
}
.p-pager-btn:hover:not(:disabled) { background: var(--cream); border-color: var(--mist); }
.p-pager-btn:disabled { opacity: .35; cursor: not-allowed; }
.p-pager-btn svg { width: 14px; height: 14px; }

/* ============================================================== misc ===== */
.p-avatar {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--cotton);
  color: var(--ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .02em;
  flex: none;
  overflow: hidden;
  text-transform: uppercase;
}
.p-avatar img { width: 100%; height: 100%; object-fit: cover; }
.p-avatar--sm { width: 26px; height: 26px; font-size: 10px; }
.p-avatar--lg { width: 52px; height: 52px; font-size: 17px; }
.p-avatar--ink { background: var(--ink); color: #fff; }

/* activity / milestone timeline */
.p-timeline { position: relative; padding-left: 26px; }
.p-timeline::before {
  content: '';
  position: absolute;
  left: 5px;
  top: 6px;
  bottom: 6px;
  width: 1px;
  background: var(--hairline);
}
.p-tl { position: relative; padding: 0 0 22px; }
.p-tl:last-child { padding-bottom: 0; }
.p-tl::before {
  content: '';
  position: absolute;
  left: -26px;
  top: 5px;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--canvas);
  box-shadow: inset 0 0 0 1.5px var(--mist);
}
.p-tl.is-done::before { background: var(--ink); box-shadow: none; }
.p-tl.is-now::before  { background: var(--bubblegum); box-shadow: 0 0 0 3px var(--cotton); }
.p-tl-when { font-size: 12px; color: var(--fog); font-variant-numeric: tabular-nums; }
.p-tl-what { font-size: 14px; margin-top: 2px; }
.p-tl-what b { font-weight: 600; }

.p-money { font-variant-numeric: tabular-nums; font-weight: 600; }
.p-mono  { font-variant-numeric: tabular-nums; letter-spacing: .01em; }
.p-quiet { color: var(--fog); }
.p-nowrap { white-space: nowrap; }
.p-truncate { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.p-divider { height: 1px; background: var(--hairline); border: 0; margin: 24px 0; }
.p-stack   { display: flex; flex-direction: column; gap: 14px; }
.p-row     { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.p-spacer  { margin-left: auto; }
.p-visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* danger button — site.css has no destructive variant */
.btn--danger { background: var(--danger); color: #fff; }
.btn--danger:hover { background: #8a1a1a; color: #fff; }
.btn--quiet { color: var(--charcoal); background: transparent; }
.btn--quiet:hover { background: var(--cream); color: var(--ink); }

/* =========================================================== auth pages == */
.p-auth {
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}
.p-auth-panel {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 48px clamp(28px, 6vw, 88px);
  min-width: 0;
}
.p-auth-inner { width: 100%; max-width: 380px; margin: 0 auto; }
.p-auth-brand { margin-bottom: 44px; display: inline-flex; }
.p-auth-brand .logo { width: 148px; height: auto; color: var(--ink); }
.p-auth h1 {
  font-family: var(--font-title);
  font-size: clamp(28px, 3vw, 38px);
  line-height: 1.18;
  letter-spacing: -.008em;
  font-weight: 300;
}
.p-auth-sub { margin-top: 12px; font-size: 15px; color: var(--charcoal); }
.p-auth form { margin-top: 32px; display: flex; flex-direction: column; gap: 18px; }
.p-auth .btn { width: 100%; }
.p-auth-alt { margin-top: 22px; font-size: 13.5px; color: var(--fog); }
.p-auth-alt a { color: var(--ink); font-weight: 500; text-decoration: underline; text-underline-offset: 3px; }
.p-auth-note { font-size: 13px; line-height: 1.55; }

/* The right half is not a photograph. It is the studio's letterhead, stood
   up: the ink field the documents behind this door are headed with, one
   line about what is inside, and the client's words at the bottom. No
   wordmark here: the form side already carries it, and two marks on one
   screen is one too many. Ink is also the one ground the foil seam on the
   join is allowed to live on. The old stock photo said nothing and was
   already carrying five other pages. */
.p-auth-media {
  position: relative;
  overflow: hidden;
  background: var(--ink);
  color: #fff;
}
.p-auth-ink {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding: clamp(32px, 4vw, 56px) clamp(28px, 4vw, 56px);
}
.p-auth-ink-line {
  margin: auto 0;
  font-family: var(--font-title);
  font-size: clamp(30px, 3vw, 46px);
  line-height: 1.12;
  letter-spacing: -.014em;
  font-weight: 300;
  max-width: 13ch;
}
.p-auth-ink-line b { font-weight: 600; }
.p-auth-quote { margin-top: auto; }
.p-auth-quote p { font-size: clamp(15px, 1.3vw, 18px); line-height: 1.45; font-weight: 400; letter-spacing: -.005em; color: rgba(255,255,255,.82); }
.p-auth-quote span { display: block; margin-top: 12px; font-size: 11px; letter-spacing: .07em; text-transform: uppercase; color: rgba(255,255,255,.55); }

/* ========================================================== documents ==== */
/* A proposal (and, in phase 4, an invoice) is a document, not a screen: one
   reading column, generous leading, and a rule between parts rather than a
   card around each. The same markup prints — see the print sheet below. */
.p-doc {
  background: #fff;
  border: 1px solid var(--hairline);
  border-radius: var(--p-r);
  padding: 44px 46px 40px;
  max-width: 820px;
}
.p-doc-head { display: flex; gap: 24px; align-items: flex-start; flex-wrap: wrap; }
.p-doc-head > div:first-child { flex: 1; min-width: 220px; }
.p-doc-num {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--fog);
  font-variant-numeric: tabular-nums;
}
.p-doc-title {
  font-family: var(--font-title);
  font-size: clamp(23px, 2.4vw, 30px);
  font-weight: 300;
  letter-spacing: -.006em;
  line-height: 1.25;
  margin-top: 10px;
}
.p-doc-sum { font-size: 15.5px; line-height: 1.65; color: var(--charcoal); margin-top: 14px; max-width: 62ch; }
.p-doc-facts { display: flex; gap: 28px; flex-wrap: wrap; margin-top: 26px; }
.p-doc-fact span {
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--fog);
  margin-bottom: 5px;
}
.p-doc-fact b { font-size: 14.5px; font-weight: 600; font-variant-numeric: tabular-nums; }
.p-doc-sec { margin-top: 36px; padding-top: 30px; border-top: 1px solid var(--hairline); }
.p-doc-sec h3 {
  font-family: var(--font-title);
  font-size: 17px;
  font-weight: 300;
  letter-spacing: -.004em;
  margin-bottom: 12px;
}
.p-doc-body { font-size: 15px; line-height: 1.7; color: var(--charcoal); white-space: pre-wrap; max-width: 66ch; }

/* line items, read-only */
.p-lines { width: 100%; border-collapse: collapse; }
.p-lines th {
  text-align: left;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--fog);
  padding: 0 0 10px;
  border-bottom: 1px solid var(--hairline);
}
.p-lines th.num, .p-lines td.num { text-align: right; font-variant-numeric: tabular-nums; }
.p-lines td { padding: 15px 0; border-bottom: 1px solid var(--hairline); vertical-align: top; font-size: 14.5px; }
.p-lines td + td, .p-lines th + th { padding-left: 18px; }
.p-lines .p-line-t { font-weight: 600; }
.p-lines .p-line-d { font-size: 13px; color: var(--fog); margin-top: 4px; line-height: 1.55; max-width: 46ch; }
.p-lines tr.is-optional td { background: var(--cream); }
.p-lines tr.is-optional.is-off td { opacity: .58; }
.p-opt-tag {
  display: inline-block;
  margin-left: 8px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--info);
  vertical-align: 1px;
}

.p-totals { margin-top: 22px; margin-left: auto; width: min(340px, 100%); }
.p-totals div { display: flex; justify-content: space-between; gap: 20px; padding: 8px 0; font-size: 14.5px; }
.p-totals dt, .p-totals span:first-child { color: var(--fog); }
.p-totals b { font-variant-numeric: tabular-nums; font-weight: 600; }
.p-totals .p-totals-grand {
  border-top: 1px solid var(--ink);
  margin-top: 6px;
  padding-top: 14px;
  font-size: 18px;
}
.p-totals .p-totals-grand span:first-child { color: var(--ink); font-weight: 600; }
.p-totals .p-totals-grand b { font-size: 21px; letter-spacing: -.02em; }

/* the decision panel at the foot of a live proposal */
.p-decide {
  margin-top: 34px;
  border: 1px solid var(--ink);
  border-radius: var(--p-r);
  padding: 26px 28px;
  background: var(--cotton);
}
.p-decide h3 { font-size: 17px; font-weight: 700; letter-spacing: -.012em; }
.p-decide p { font-size: 14px; color: var(--charcoal); line-height: 1.6; margin-top: 8px; max-width: 58ch; }
.p-sign-input {
  font-size: 19px;
  letter-spacing: .01em;
  padding: 13px 16px;
}
.p-decided {
  margin-top: 34px;
  border: 1px solid var(--hairline);
  border-left: 3px solid var(--ok);
  border-radius: var(--p-r);
  padding: 22px 26px;
  background: var(--ok-soft);
}
.p-decided.is-no { border-left-color: var(--muted); background: var(--cream); }
.p-decided b { font-weight: 600; }
.p-decided p { font-size: 14px; line-height: 1.6; margin-top: 6px; color: var(--charcoal); }

/* ---- the builder: line items as editable rows ------------------------- */
.p-edit-line {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 78px 130px 116px 34px;
  gap: 10px;
  align-items: start;
  padding: 12px 0;
  border-bottom: 1px solid var(--hairline);
}
.p-edit-line .p-input { padding: 9px 11px; font-size: 14px; }
.p-edit-line .p-amount {
  align-self: center;
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  font-size: 14px;
  padding-right: 2px;
}
.p-edit-line .p-x { align-self: center; }
.p-edit-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 78px 130px 116px 34px;
  gap: 10px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--hairline);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--fog);
}
.p-edit-head span:nth-child(n + 2) { text-align: right; }
.p-edit-head span:nth-child(2) { text-align: left; }
.p-edit-sub { grid-column: 1 / -1; margin-top: -2px; }
.p-edit-sub .p-input { font-size: 13px; }

@media (max-width: 720px) {
  .p-doc { padding: 26px 20px 28px; }
  .p-edit-line, .p-edit-head { grid-template-columns: minmax(0, 1fr) 68px 108px; }
  .p-edit-line .p-amount, .p-edit-head span:nth-child(4) { display: none; }
  .p-edit-line .p-x { grid-column: 3; justify-self: end; }
  .p-edit-head span:nth-child(5) { display: none; }
}

/* ========================================================= conversation == */
/* A thread is a reading column with a composer welded to the bottom, not a
   chat app: the messages are long-form more often than not. */
.p-thread {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--hairline);
  border-radius: var(--p-r);
  background: #fff;
  overflow: hidden;
  max-height: min(70vh, 720px);
}
.p-msgs { flex: 1; overflow-y: auto; padding: 24px; scroll-behavior: smooth; }

.p-msg { display: flex; gap: 12px; padding: 10px 0; align-items: flex-start; }
.p-msg.is-mine { flex-direction: row-reverse; }
.p-msg-body { min-width: 0; max-width: 68%; }
.p-msg.is-mine .p-msg-body { margin-left: auto; }
.p-msg-meta {
  display: flex;
  gap: 8px;
  align-items: baseline;
  font-size: 12px;
  color: var(--fog);
  margin-bottom: 5px;
}
.p-msg.is-mine .p-msg-meta { justify-content: flex-end; }
.p-msg-meta b { font-weight: 600; color: var(--charcoal); font-size: 12.5px; }
.p-msg-text {
  font-size: 14.5px;
  line-height: 1.6;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  background: var(--cream);
  border-radius: var(--r-panel);
  padding: 12px 15px;
}
.p-msg.is-mine .p-msg-text { background: var(--ink); color: #fff; }

.p-msg-files { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.p-msg.is-mine .p-msg-files { justify-content: flex-end; }
.p-msg-file {
  display: inline-flex;
  gap: 8px;
  align-items: baseline;
  border: 1px solid var(--hairline);
  border-radius: var(--p-r);
  padding: 7px 11px;
  font-size: 12.5px;
  background: var(--canvas);
  transition: border-color .18s var(--ease);
}
.p-msg-file:hover { border-color: var(--ink); }

/* A file in a list rather than on a message: same chip, plus room for the
   badge that says whether it has gone any further than the studio. */
.p-filerow {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 0;
}
.p-filerow + .p-filerow { border-top: 1px solid var(--hairline); }
.p-filerow .p-msg-file { min-width: 0; }
.p-filerow .p-msg-file span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.p-composer { border-top: 1px solid var(--hairline); padding: 16px 20px; background: var(--canvas); }
.p-composer .p-textarea { resize: vertical; }
.p-composer-foot { display: flex; align-items: center; gap: 12px; margin-top: 12px; }

.p-threadrow {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  padding: 15px 20px;
  border-bottom: 1px solid var(--hairline);
  transition: background .18s var(--ease);
}
.p-threadrow:hover { background: var(--cream); }
.p-threadrow.is-active { background: var(--cotton); }
.p-threadrow-main { flex: 1; min-width: 0; }
.p-threadrow-subject { font-size: 14.5px; font-weight: 600; }
.p-threadrow-preview {
  font-size: 13px;
  color: var(--fog);
  margin-top: 3px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.p-unread {
  min-width: 20px; height: 20px; padding: 0 6px;
  border-radius: var(--r-pill);
  background: var(--bubblegum);
  color: var(--ink);
  font-size: 11px; font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
  font-variant-numeric: tabular-nums;
  flex: none;
}

@media (max-width: 640px) {
  .p-msg-body { max-width: 84%; }
  .p-msgs { padding: 16px; }
}

/* --------------------------------------------------- two-pane screens --- */
/* Thread list beside the conversation. Inline styles cannot be overridden by a
   media query, which is the whole reason this is a class: on a phone the panes
   stack, and the list goes first because choosing a conversation has to come
   before reading one. */
.p-twopane {
  display: grid;
  gap: var(--gap, 18px);
  grid-template-columns: minmax(260px, 340px) minmax(0, 1fr);
  align-items: start;
}

@media (max-width: 860px) {
  .p-twopane { grid-template-columns: minmax(0, 1fr); }
  /* A full-height message list above the conversation would push it off the
     screen; cap it and let it scroll. */
  .p-twopane > .p-card--flush { max-height: 42vh; overflow-y: auto; }
  .p-thread { max-height: none; }
}

/* ============================================================= responsive  */
@media (max-width: 1080px) {
  .p-grid--split { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 900px) {
  .p-shell { grid-template-columns: minmax(0, 1fr); }
  .p-rail {
    position: fixed;
    z-index: 110;
    left: 0;
    top: 0;
    width: min(300px, 86vw);
    transform: translateX(-100%);
    transition: transform .3s var(--ease);
    box-shadow: var(--shadow-float);
  }
  .p-rail.is-open { transform: none; }
  .p-railtoggle { display: block; }
  .p-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 105;
    background: rgba(0, 0, 0, .34);
    opacity: 0;
    pointer-events: none;
    transition: opacity .24s var(--ease);
  }
  .p-scrim.is-in { opacity: 1; pointer-events: auto; }
  .p-auth { grid-template-columns: minmax(0, 1fr); }
  .p-auth-media { display: none; }
}

@media (max-width: 640px) {
  .p-view { padding: 20px 16px 88px; }
  .p-topbar { padding: 0 16px; gap: 12px; }
  .p-card { padding: 16px 16px; }
  .p-card-head, .p-card-body, .p-card-foot { padding-left: 16px; padding-right: 16px; }
  .p-kv > div { flex-direction: column; gap: 3px; align-items: flex-start; }
  .p-kv dd { margin-left: 0; text-align: left; }
  .p-toasts { left: 16px; right: 16px; bottom: 16px; max-width: none; }
  /* A box floating in the middle of a phone wastes the edges and puts its
     buttons where a thumb is not. It sits on the bottom edge instead and
     rises into place, the same sheet the public site uses. */
  .p-modal {
    left: 0;
    right: 0;
    top: auto;
    bottom: 0;
    width: 100%;
    max-height: 92dvh;
    transform: translateY(100%);
    border-radius: var(--r-sheet) var(--r-sheet) 0 0;
    padding-bottom: env(safe-area-inset-bottom, 0px);
    transition: transform .34s var(--ease), opacity .24s var(--ease);
  }
  .p-modal--wide { width: 100%; }
  .p-modal.is-in { transform: none; }
  /* The drawer is already an edge panel; on a phone it just fills the width. */
  .p-drawer { width: 100vw; }
  .p-modal-body, .p-drawer-body, .p-modal-head, .p-drawer-head, .p-modal-foot, .p-drawer-foot {
    padding-left: 18px;
    padding-right: 18px;
  }
  /* Stacked, so the primary action is not a thumb-stretch away in a row. */
  .p-modal-foot { flex-wrap: wrap; }
  .p-modal-foot .btn { flex: 1 1 auto; justify-content: center; }
}

@media (prefers-reduced-motion: reduce) {
  .p-skel { animation: none; background: #f2f2f2; }
  .p-spin { animation-duration: 1.6s; }
}

/* ================================================================= foil == */
/* The Ultrabasic foil, in the portal.

   Everything here composes from --brand-foil in site.css. Do not write another
   gradient, do not substitute an even rainbow (the near-black anchors are what
   read as metal), and never hard-stop it — at these sizes a 1px band aliases
   into a white slash.

   **The foil needs a dark ground and some area.** The near-black anchors are
   what read as metal, and they have nothing to bite on over white. Every
   attempt to run it as a hairline over the portal's chrome — the topbar, the
   rail lockup, the top edge of a white document card — was built, looked at,
   and pulled back out: on a stylesheet whose whole structural language is
   hairlines, a coloured one reads as a decorated divider, not as a brand.
   Do not try it again. If a new placement cannot give the foil a dark field
   (the letterhead), a closed curve (the avatar ring), or a mask (the wordmark),
   it is the wrong placement.

   Where it does run:
     · the letterhead opening a proposal or an invoice — the documents are the
       artefacts, the one part of this product a client keeps and prints
     · the signed-in avatar, ringed
     · the wordmark, which only appears if you go looking for it
     · the loading shimmer, and the progress fill
     · nothing on the data, and nothing state-dependent. No foil on cards,
       badges, rows, tabs or the active nav item: status colour and ink weight
       are load-bearing there, and a foil surface that comes and goes reads as
       an alarm rather than as the brand. */

/* ---- the letterhead ---------------------------------------------------- */
/* One markup, three designs, chosen by LETTERHEAD in assets/js/portal/brand.js
   so the screen document and the drawn PDF never disagree.

   None of them is a coloured bar with a logo in it. That was the first attempt
   and it was thrown out: it is what every word processor's template already
   looks like, and a document worth drawing by hand should not open like one. */
.p-doc { position: relative; overflow: hidden; }
.p-lh { position: relative; }
.p-lh-mark { position: relative; display: block; }
.p-lh-mark img { display: block; width: 100%; height: auto; }
.p-lh-kind {
  display: block;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--fog);
}
.p-lh-party { display: block; }

/* --- A · Foil -----------------------------------------------------------
   The wordmark with the foil inside the letterforms, alone on a white page.
   This is the site's holographic mark brought onto paper — the same two
   layers as the header hover: the black wordmark, and over it a pool of foil
   masked to the same shape. Nothing else competes with it. */
.p-lh--foil {
  display: grid;
  grid-template-columns: auto auto;
  align-items: end;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 34px;
  padding-bottom: 24px;
  border-bottom: 1px solid var(--hairline);
}
.p-lh--foil .p-lh-mark { width: 232px; }
/* Masked to the wordmark, so the foil only exists inside the letterforms.
   The <img> stays underneath: if mask-image is unsupported the mark is simply
   black, which is a fine letterhead rather than a broken one. */
.p-lh--foil .p-lh-foil {
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, var(--brand-foil));
  background-size: 200% 100%;
  background-position: 0% 50%;
  animation: foilRibbon 11s linear infinite;
  -webkit-mask-image: url("../../ULTRABASIC.svg");
          mask-image: url("../../ULTRABASIC.svg");
  -webkit-mask-size: 100% 100%;
          mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
}
.p-lh--foil .p-lh-meta { text-align: right; padding-bottom: 2px; }
.p-lh--foil .p-lh-party {
  margin-top: 5px;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -.014em;
  color: var(--ink);
}

/* --- B · Poster ---------------------------------------------------------
   The document announces itself, in the same serif the marketing site sets
   its headlines in. The foil is a thick bar pinned under the word; the
   wordmark steps back to a caption. Sentence case, not uppercase: at this
   size Merriweather's capitals are the whole point, and shouting every
   letter throws away the shape of the word. */
.p-lh--poster { margin-bottom: 36px; }
.p-lh--poster .p-lh-mark { width: 96px; }
.p-lh--poster .p-lh-meta {
  display: flex;
  flex-direction: column-reverse;
}
.p-lh--poster .p-lh-kind {
  font-family: var(--font-title);
  font-size: clamp(44px, 8vw, 68px);
  font-weight: 300;
  letter-spacing: -.01em;
  line-height: 1.04;
  text-transform: none;
  color: var(--ink);
  margin-top: 22px;
  padding-bottom: 14px;
  border-bottom: 7px solid transparent;
  border-image: linear-gradient(90deg, var(--brand-foil)) 1;
}
.p-lh--poster .p-lh-party {
  margin-top: -22px;   /* pulled up beside the wordmark, not under the word */
  text-align: right;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--fog);
}

/* --- C · Spine ----------------------------------------------------------
   The foil leaves the header and becomes the edge of the paper, full height.
   The header is then almost nothing, and the brand is still on every page —
   the only one of the three that keeps working on page four. */
.p-lh--spine {
  position: static;      /* so the bar below measures against .p-doc */
  display: grid;
  grid-template-columns: auto auto;
  align-items: start;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 34px;
}
.p-lh--spine::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 9px;
  background: linear-gradient(180deg, var(--brand-foil));
  background-size: 100% 200%;
  background-position: 50% 0%;
  animation: foilSeam 14s linear infinite;
}
.p-lh--spine .p-lh-mark { width: 168px; }
.p-lh--spine .p-lh-meta { text-align: right; }
.p-lh--spine .p-lh-party {
  margin-top: 5px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -.012em;
  color: var(--ink);
}
/* The document's own text clears the bar. */
.p-doc:has(.p-lh--spine) { padding-left: 62px; }

@media (max-width: 640px) {
  .p-lh--foil, .p-lh--spine {
    grid-template-columns: minmax(0, 1fr);
    justify-content: start;
  }
  .p-lh--foil .p-lh-meta, .p-lh--spine .p-lh-meta { text-align: left; }
  .p-lh--foil .p-lh-mark { width: min(232px, 70vw); }
  .p-lh--poster .p-lh-party { margin-top: 8px; text-align: left; }
  .p-doc:has(.p-lh--spine) { padding-left: 34px; }
}

/* ---- the signed-in avatar ---------------------------------------------- */
/* A closed curve is the one small shape the foil survives at — no ends to
   alias, and a conic sweep has somewhere to go. Filling the disc with it
   swallows the initials, so the foil is the ring and the ink is the ground. */
.p-avatar--foil {
  border: 2px solid transparent;
  background:
    linear-gradient(var(--deep), var(--deep)) padding-box,
    conic-gradient(from var(--holo-angle), var(--brand-foil)) border-box;
  color: #fff;
  animation: askHolo 7s linear infinite;
}

/* ---- the loading shimmer ----------------------------------------------- */
/* The foil is deliberately NOT on the skeleton. It was, at .18, and the reasoning
   was that it costs nothing and disappears the moment data lands — but a
   skeleton is the one surface with no content to be branded, and a tinted bar
   reads as something rather than as an absence. It also fought the sweep: two
   gradients travelling at different rates on a 14px bar. The plain grey sweep
   above says "loading" and nothing else, which is its whole job. */

/* ---- the holographic wordmark ------------------------------------------ */
/* .holo-mark ships the spotlight tuned for the site header's 138px mark; the
   rail's is 108px, so its pool shrinks to match. The auth pages' 148px is
   close enough to the default to leave alone. */
.p-rail-brand [data-holo] { --holo-pool: 56px; --holo-bloom: 34px; }

/* ---- auth pages: the arrival moment ------------------------------------ */
/* A 2px foil seam on the panel/media join. The shade over the photo stays
   flat — foil behind the quote would wreck its contrast. */
.p-auth-media::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 2px;
  z-index: 2;
  background: linear-gradient(180deg, var(--brand-foil));
  background-size: 100% 200%;
  background-position: 50% 0%;
  animation: foilSeam 11s linear infinite;
}
@keyframes foilSeam { to { background-position: 50% 100%; } }

/* ---- progress ---------------------------------------------------------- */
/* The one number in the product that deserves to feel good. Static: a bar that
   both fills and shimmers is a bar nobody can read.
   Sized in px, not %, so the ramp keeps one constant scale instead of being
   crushed into a 10%-wide fill — which also means a bar starts at the ramp's
   near-black anchor and literally colours up as the project progresses.
   The stop list is written twice, so 900px is one repeat per 450px: a full-width
   bar lands inside a single sweep. Tighter than that and it repeats within one
   bar, which is the exact thing that turns foil back into a rainbow. */
.p-progress > i {
  background: linear-gradient(90deg, var(--brand-foil));
  background-size: 900px 100%;
  background-repeat: repeat-x;
}
.p-progress--ok > i { background: var(--ok); }

@media (prefers-reduced-motion: reduce) {
  .p-lh--foil .p-lh-foil,
  .p-lh--spine::before,
  .p-avatar--foil,
  .p-auth-media::before { animation: none; }
}

@media print {
  .p-auth-media::before { display: none; }
  .p-progress > i { background: #000; }
  /* Cmd+P on a document screen. The real PDF is drawn in assets/js/portal/pdf/
     and none of this applies to it.
     The foil is the letterhead in every design here, so it has to survive the
     print engine's default of dropping backgrounds. */
  .p-lh, .p-lh * {
    -webkit-print-color-adjust: exact;
            print-color-adjust: exact;
  }
  .p-lh--foil .p-lh-foil, .p-lh--spine::before { animation: none; }
  /* The spine is a screen and PDF device; on a browser print it would run into
     the unprintable margin on most printers. */
  .p-lh--spine::before { display: none; }
  .p-doc:has(.p-lh--spine) { padding-left: 0; }
}

/* ================================================================ print == */
/* Invoices and proposals are "downloaded" by printing to PDF, so the print
   sheet is a real deliverable rather than an afterthought. */
@media print {
  .p-rail, .p-topbar, .p-toasts, .p-scrim, .p-scrimlayer,
  .p-head-actions, .p-tabs, .p-filters, .p-pager, .no-print { display: none !important; }
  .p-shell { display: block; }
  .p-view { padding: 0; max-width: none; }
  .p-card, .p-tablewrap { border: 0; border-radius: 0; }
  .p-doc { border: 0; padding: 0; max-width: none; }
  .p-decide, .p-crumbs { display: none !important; }
  .p-decided { background: transparent; border: 1px solid #999; }
  .p-lines tr.is-optional td { background: transparent; }
  .p-table th { background: transparent; border-bottom: 1px solid #000; }
  .p-table td { border-bottom: 1px solid #ddd; }
  .p-badge { border: 1px solid #999; background: transparent !important; color: #000 !important; }
  .p-badge::before { display: none; }
  .print-only { display: block !important; }
  a[href]::after { content: ''; }
  body { background: #fff; }
  @page { margin: 16mm; }
}
.print-only { display: none; }

/* ---- a rating, on the hiring drawer -------------------------------------- */
/* Real buttons rather than a radio group: each one has to be independently
   clickable to *set* that value, and a radio group would need five labels and
   five ids to say the same thing. */
.p-stars { display: inline-flex; gap: 2px; }
.p-star {
  font-size: 20px;
  line-height: 1;
  padding: 2px 3px;
  color: var(--mist);
  background: none;
  border: 0;
  cursor: pointer;
  transition: color .16s var(--ease), transform .16s var(--ease);
}
.p-star:hover { color: var(--fog); transform: translateY(-1px); }
.p-star.is-on { color: var(--ink); }

/* ---------------------------------------------------- the studio's objects -- */
/* The isometric icons (scripts/isoicons.py). One stroke in CSS px that does
   not scale with the drawing; faces take the surface they stand on so the
   edges behind them disappear, which is why each surface names its fill. */
.iso { display: block; width: 100%; height: 100%; overflow: visible; color: inherit; }
.iso path { fill: none; stroke: currentColor; stroke-width: 1.1px; vector-effect: non-scaling-stroke; stroke-linejoin: round; stroke-linecap: round; }
.iso .iso-face { fill: var(--iso-fill, var(--canvas)); }
.iso .iso-dash { stroke-dasharray: 3 3; }
.p-rail { --iso-fill: var(--cream); }
.p-nav:hover { --iso-fill: var(--canvas); }
.p-nav.is-active { --iso-fill: var(--ink); }
.p-nav svg.iso { width: 20px; height: 20px; }
.p-empty-mark svg.iso { width: 44px; height: 44px; }
.p-palette-ico svg.iso { width: 17px; height: 17px; }
