/* ==========================================================================
   Priostack Apps design system - components.css
   --------------------------------------------------------------------------
   CSS only: the IFML engine (or any server template) renders the markup
   documented in web/ds/README.md and these rules style it. Needs tokens.css
   and base.css first.

   Conventions
   - Every class starts with ps-: block, block__element, block--modifier.
   - State lives in ARIA attributes where ARIA has one (aria-invalid,
     aria-current, aria-selected, aria-disabled) and in data-state otherwise
     (buttons: idle | working | done | error; result: empty; connect:
     connected). One bound attribute per element is enough to drive a state.
   - Messages that may be empty (field errors, action status, toast) collapse
     when the element has no children, so an engine binds text only.
   - Components lay themselves out from their own width (container queries),
     so they behave the same in a page, a side panel or a gallery frame.
   - Hover styles only apply on devices that hover; every interactive control
     is at least 44px tall on touch screens; transitions are 150 ms at most
     and none under prefers-reduced-motion.
   - Colours only come from tokens: tests/ds checks every pair for contrast.
   ========================================================================== */

/* ==== Icons ===============================================================
   Mask icons painted with currentColor: <span class="ps-icon ps-icon--copy"
   aria-hidden="true"></span>. 24px grid, 2px strokes. Data URIs only (CSP
   img-src 'self' data:), nothing is downloaded. */
:root {
  --ps-i-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='9' y='9' width='12' height='12' rx='2'/%3E%3Cpath d='M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1'/%3E%3C/svg%3E");
  --ps-i-download: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'/%3E%3Cpath d='m7 10 5 5 5-5'/%3E%3Cpath d='M12 15V3'/%3E%3C/svg%3E");
  --ps-i-upload: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m16 16-4-4-4 4'/%3E%3Cpath d='M12 12v9'/%3E%3Cpath d='M20.4 18.4A5 5 0 0 0 18 9h-1.3A8 8 0 1 0 3 16.3'/%3E%3C/svg%3E");
  --ps-i-print: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9V2h12v7'/%3E%3Cpath d='M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2'/%3E%3Crect x='6' y='14' width='12' height='8' rx='1'/%3E%3C/svg%3E");
  --ps-i-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E");
  --ps-i-clock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7v5l3 2'/%3E%3C/svg%3E");
  --ps-i-alert: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7.5v5'/%3E%3Cpath d='M12 16.5h.01'/%3E%3C/svg%3E");
  --ps-i-info: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 16.5v-5'/%3E%3Cpath d='M12 7.5h.01'/%3E%3C/svg%3E");
  --ps-i-warning: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z'/%3E%3Cpath d='M12 9v4'/%3E%3Cpath d='M12 17h.01'/%3E%3C/svg%3E");
  --ps-i-success: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='m8 12.5 2.7 2.7L16 9.5'/%3E%3C/svg%3E");
  --ps-i-plus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 5v14'/%3E%3Cpath d='M5 12h14'/%3E%3C/svg%3E");
  --ps-i-minus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3C/svg%3E");
  --ps-i-close: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E");
  --ps-i-trash: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 6h18'/%3E%3Cpath d='M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6'/%3E%3Cpath d='M10 11v6'/%3E%3Cpath d='M14 11v6'/%3E%3Cpath d='M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2'/%3E%3C/svg%3E");
  --ps-i-chevron-right: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 18 6-6-6-6'/%3E%3C/svg%3E");
  --ps-i-chevron-down: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  --ps-i-arrow-right: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='m13 6 6 6-6 6'/%3E%3C/svg%3E");
  --ps-i-external: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/%3E%3Cpath d='M15 3h6v6'/%3E%3Cpath d='M10 14 21 3'/%3E%3C/svg%3E");
  --ps-i-globe: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M3 12h18'/%3E%3Cpath d='M12 3a14 14 0 0 1 0 18a14 14 0 0 1 0-18z'/%3E%3C/svg%3E");
  --ps-i-link: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 13a5 5 0 0 0 7.5.5l3-3a5 5 0 0 0-7-7l-1.7 1.7'/%3E%3Cpath d='M14 11a5 5 0 0 0-7.5-.5l-3 3a5 5 0 0 0 7 7l1.7-1.7'/%3E%3C/svg%3E");
  --ps-i-grid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='3' width='7' height='7' rx='1.5'/%3E%3Crect x='14' y='3' width='7' height='7' rx='1.5'/%3E%3Crect x='3' y='14' width='7' height='7' rx='1.5'/%3E%3Crect x='14' y='14' width='7' height='7' rx='1.5'/%3E%3C/svg%3E");
  --ps-i-percent: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19 5 5 19'/%3E%3Ccircle cx='6.5' cy='6.5' r='2.5'/%3E%3Ccircle cx='17.5' cy='17.5' r='2.5'/%3E%3C/svg%3E");
  --ps-i-receipt: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 2v20l3-2 2 2 2-2 2 2 2-2 3 2V2l-3 2-2-2-2 2-2-2-2 2z'/%3E%3Cpath d='M9 8h6'/%3E%3Cpath d='M9 12h6'/%3E%3Cpath d='M9 16h4'/%3E%3C/svg%3E");
  --ps-i-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2'/%3E%3Cpath d='M16 2v4'/%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
  --ps-i-calculator: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4' y='2' width='16' height='20' rx='2'/%3E%3Cpath d='M8 6h8'/%3E%3Cpath d='M8 11h.01'/%3E%3Cpath d='M12 11h.01'/%3E%3Cpath d='M16 11h.01'/%3E%3Cpath d='M8 15h.01'/%3E%3Cpath d='M12 15h.01'/%3E%3Cpath d='M16 15v3'/%3E%3Cpath d='M8 18.5h4'/%3E%3C/svg%3E");
  --ps-i-timer: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='13' r='8'/%3E%3Cpath d='M12 9v4l2 2'/%3E%3Cpath d='M10 2h4'/%3E%3C/svg%3E");
}

.ps-icon {
  display: inline-block;
  flex: none;
  width: 1.25em;
  height: 1.25em;
  vertical-align: -0.25em;
  background-color: currentColor;
  -webkit-mask: var(--ps-icon) center / contain no-repeat;
  mask: var(--ps-icon) center / contain no-repeat;
}

.ps-icon--copy { --ps-icon: var(--ps-i-copy); }
.ps-icon--download { --ps-icon: var(--ps-i-download); }
.ps-icon--upload { --ps-icon: var(--ps-i-upload); }
.ps-icon--print { --ps-icon: var(--ps-i-print); }
.ps-icon--check { --ps-icon: var(--ps-i-check); }
.ps-icon--clock { --ps-icon: var(--ps-i-clock); }
.ps-icon--alert { --ps-icon: var(--ps-i-alert); }
.ps-icon--info { --ps-icon: var(--ps-i-info); }
.ps-icon--warning { --ps-icon: var(--ps-i-warning); }
.ps-icon--success { --ps-icon: var(--ps-i-success); }
.ps-icon--plus { --ps-icon: var(--ps-i-plus); }
.ps-icon--minus { --ps-icon: var(--ps-i-minus); }
.ps-icon--close { --ps-icon: var(--ps-i-close); }
.ps-icon--trash { --ps-icon: var(--ps-i-trash); }
.ps-icon--chevron-right { --ps-icon: var(--ps-i-chevron-right); }
.ps-icon--chevron-down { --ps-icon: var(--ps-i-chevron-down); }
.ps-icon--arrow-right { --ps-icon: var(--ps-i-arrow-right); }
.ps-icon--external { --ps-icon: var(--ps-i-external); }
.ps-icon--globe { --ps-icon: var(--ps-i-globe); }
.ps-icon--link { --ps-icon: var(--ps-i-link); }
.ps-icon--grid { --ps-icon: var(--ps-i-grid); }
.ps-icon--percent { --ps-icon: var(--ps-i-percent); }
.ps-icon--receipt { --ps-icon: var(--ps-i-receipt); }
.ps-icon--calendar { --ps-icon: var(--ps-i-calendar); }
.ps-icon--calculator { --ps-icon: var(--ps-i-calculator); }
.ps-icon--timer { --ps-icon: var(--ps-i-timer); }

/* ==== App shell =========================================================== */
.ps-page {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
}

.ps-page > .ps-main {
  flex: 1 0 auto;
}

.ps-container {
  width: 100%;
  max-width: calc(var(--ps-container) + 2 * var(--ps-gutter));
  margin-inline: auto;
  padding-inline: var(--ps-gutter);
}

.ps-skip {
  position: absolute;
  z-index: var(--ps-z-toast);
  top: var(--ps-space-2);
  left: var(--ps-space-2);
  padding: var(--ps-space-2) var(--ps-space-4);
  border-radius: var(--ps-radius-control);
  background-color: var(--ps-surface);
  color: var(--ps-link);
  font-weight: var(--ps-weight-semibold);
  transform: translateY(-200%);
}

/* The shadow only here: from above the page it still reaches down into the corner of every page. */
.ps-skip:focus {
  box-shadow: var(--ps-shadow-lg);
  transform: none;
}

/* Header: brand (links to the hub), text links, locale switch, connect. */
.ps-header {
  container: ps-header / inline-size;
  border-bottom: 1px solid var(--ps-line);
  background-color: var(--ps-surface);
  color: var(--ps-text);
}

.ps-header__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ps-space-2);
  min-height: 3.5rem;
  padding-block: var(--ps-space-1);
}

.ps-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--ps-space-2);
  min-height: var(--ps-target);
  color: var(--ps-text);
  font-weight: var(--ps-weight-bold);
  letter-spacing: var(--ps-tracking-tight);
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
}

.ps-brand:hover {
  color: var(--ps-text);
}

/* Priostack's mark, the art of its favicon. It is transparent and keeps its own colours, which read
   on the light and the dark surface alike. */
.ps-brand__mark {
  display: block;
  flex: none;
  height: 1.75rem;
  line-height: 0;
}

.ps-brand__mark img {
  display: block;
  width: auto;
  height: 100%;
}

.ps-brand__name {
  font-size: 1.0625rem;
}

.ps-brand__suffix {
  color: var(--ps-link);
  font-weight: var(--ps-weight-semibold);
}

.ps-header__nav {
  display: none;
}

.ps-header__link {
  display: inline-flex;
  align-items: center;
  gap: var(--ps-space-2);
  min-height: var(--ps-target);
  padding-inline: var(--ps-space-3);
  border-radius: var(--ps-radius-control);
  color: var(--ps-text);
  font-size: var(--ps-text-sm);
  font-weight: var(--ps-weight-semibold);
  text-decoration: none;
}

.ps-header__link[aria-current="page"] {
  color: var(--ps-link);
}

@media (hover: hover) {
  .ps-header__link:hover {
    background-color: var(--ps-wash);
    color: var(--ps-text);
  }
}

/* Words shown only in a wide header: "Connect<span class=ps-header__wide> to
   Priostack</span>" reads "Connect" on a phone. */
.ps-header__wide {
  display: none;
}

.ps-header__tools {
  display: flex;
  align-items: center;
  gap: var(--ps-space-2);
  margin-left: auto;
}

/* A narrow header keeps one line on a 360px phone: the locale switch shows
   only the other locale and the connect control drops its icon. */
.ps-header .ps-locale__link[aria-current="true"],
.ps-header .ps-locale__link[aria-current="page"],
.ps-header .ps-connect .ps-icon {
  display: none;
}

.ps-header .ps-locale .ps-locale__link {
  border-left: 0;
  border-radius: calc(var(--ps-radius-control) - 1px);
}

/* A phone's header that also holds the Connect control keeps its one line by showing the mark alone:
   "Priostack Apps" is the wider half of the brand, and it stays the link's name for a screen reader.
   Without the control, the whole brand fits down to 320px. */
@container ps-header (max-width: 480px) {
  .ps-header__inner:has(.ps-connect) .ps-brand__name {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

@container ps-header (min-width: 600px) {
  .ps-header__inner {
    gap: var(--ps-space-3);
    min-height: 4rem;
  }

  .ps-header__nav {
    display: flex;
    align-items: center;
    gap: var(--ps-space-1);
    margin-left: auto;
  }

  .ps-header__tools {
    margin-left: 0;
  }

  .ps-header__wide {
    display: inline;
  }

  .ps-header .ps-locale__link[aria-current="true"],
  .ps-header .ps-locale__link[aria-current="page"] {
    display: inline-flex;
  }

  .ps-header .ps-connect .ps-icon {
    display: inline-block;
  }

  .ps-header .ps-locale .ps-locale__link:first-child {
    border-radius: calc(var(--ps-radius-control) - 1px) 0 0 calc(var(--ps-radius-control) - 1px);
  }

  .ps-header .ps-locale .ps-locale__link:last-child {
    border-radius: 0 calc(var(--ps-radius-control) - 1px) calc(var(--ps-radius-control) - 1px) 0;
  }

  .ps-header .ps-locale .ps-locale__link + .ps-locale__link {
    border-left: 1px solid var(--ps-line-strong);
  }
}

/* Connect to Priostack: a .ps-btn; data-state="connected" adds the dot, in place of the icon. */
.ps-connect[data-state="connected"]::before {
  content: "";
  flex: none;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background-color: var(--ps-success-border);
}

.ps-header .ps-connect[data-state="connected"] .ps-icon {
  display: none;
}

/* Locale switch: one link per locale, the current one has aria-current. */
.ps-locale {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--ps-line-strong);
  border-radius: var(--ps-radius-control);
  background-color: var(--ps-surface);
}

.ps-locale__link {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--ps-target);
  min-height: var(--ps-target);
  padding-inline: var(--ps-space-2);
  color: var(--ps-text-muted);
  font-size: var(--ps-text-sm);
  font-weight: var(--ps-weight-semibold);
  letter-spacing: 0.02em;
  text-decoration: none;
}

.ps-locale__link:first-child {
  border-radius: calc(var(--ps-radius-control) - 1px) 0 0 calc(var(--ps-radius-control) - 1px);
}

.ps-locale__link:last-child {
  border-radius: 0 calc(var(--ps-radius-control) - 1px) calc(var(--ps-radius-control) - 1px) 0;
}

.ps-locale__link + .ps-locale__link {
  border-left: 1px solid var(--ps-line-strong);
}

.ps-locale__link:focus-visible {
  z-index: var(--ps-z-raised);
}

@media (hover: hover) {
  .ps-locale__link:hover {
    background-color: var(--ps-wash);
    color: var(--ps-text);
  }
}

.ps-locale__link[aria-current="true"],
.ps-locale__link[aria-current="page"] {
  background-color: var(--ps-soft);
  color: var(--ps-link-hover);
}

/* Footer: Powered by Priostack, legal links, locale links. */
.ps-footer {
  margin-top: var(--ps-space-8);
  border-top: 1px solid var(--ps-line);
  background-color: var(--ps-wash);
  color: var(--ps-text-muted);
  font-size: var(--ps-text-sm);
}

.ps-footer__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--ps-space-2) var(--ps-space-5);
  padding-block: var(--ps-space-5);
}

.ps-footer__powered {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  min-height: var(--ps-target);
  color: var(--ps-text);
  text-decoration: none;
}

.ps-footer__powered strong {
  font-weight: var(--ps-weight-bold);
}

.ps-footer__links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 var(--ps-space-1);
  margin: 0 calc(-1 * var(--ps-space-2));
  padding: 0;
  list-style: none;
}

.ps-footer__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--ps-target);
  padding-inline: var(--ps-space-2);
  color: var(--ps-text-muted);
  text-decoration: none;
}

.ps-footer__link[aria-current="true"],
.ps-footer__link[aria-current="page"] {
  color: var(--ps-text);
  font-weight: var(--ps-weight-semibold);
}

@media (hover: hover) {
  .ps-footer__powered:hover,
  .ps-footer__link:hover {
    color: var(--ps-text);
    text-decoration: underline;
  }
}

/* Breadcrumb: nav > ol > li; the current page is a span with aria-current. */
.ps-breadcrumb {
  min-width: 0; /* a long title shrinks to its ellipsis inside flex and grid parents too */
  font-size: var(--ps-text-sm);
}

.ps-breadcrumb__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ps-breadcrumb__item {
  display: inline-flex;
  align-items: center;
  min-width: 0;
  max-width: 100%;
  color: var(--ps-text);
}

.ps-breadcrumb__item + .ps-breadcrumb__item::before {
  content: "";
  flex: none;
  width: 1rem;
  height: 1rem;
  margin-inline: var(--ps-space-1);
  color: var(--ps-text-muted);
  background-color: currentColor;
  -webkit-mask: var(--ps-i-chevron-right) center / contain no-repeat;
  mask: var(--ps-i-chevron-right) center / contain no-repeat;
}

.ps-breadcrumb__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--ps-target);
  color: var(--ps-text-muted);
}

.ps-breadcrumb__current {
  min-width: 0;
  overflow: hidden;
  font-weight: var(--ps-weight-semibold);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Main and page head (H1 + one-line subtitle). */
.ps-main {
  padding-block: var(--ps-space-1) var(--ps-space-7);
}

.ps-main:focus {
  outline: none;
}

.ps-page-head {
  display: grid;
  gap: var(--ps-space-2);
  margin-block: var(--ps-space-2) var(--ps-space-4);
}

.ps-page-head__title {
  font-size: var(--ps-text-3xl);
}

.ps-page-head__subtitle {
  max-width: 44rem;
  color: var(--ps-text-muted);
  line-height: var(--ps-leading-snug);
}

@media (min-width: 900px) {
  .ps-page-head {
    margin-block: var(--ps-space-4) var(--ps-space-5);
  }

  .ps-page-head__subtitle {
    font-size: var(--ps-text-lg);
  }
}

/* ==== Tool card ===========================================================
   The app itself. Stacked on small widths; from 720px of card width, inputs
   and output sit side by side (ps-tool--wide keeps one column, for
   documents). */
.ps-tool {
  container: ps-tool / inline-size;
  border: 1px solid var(--ps-line);
  border-radius: var(--ps-radius-card);
  background-color: var(--ps-surface);
  color: var(--ps-text);
  box-shadow: var(--ps-shadow-md);
}

.ps-tool__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--ps-space-2) var(--ps-space-3);
  padding: var(--ps-space-2) var(--ps-space-4);
  border-bottom: 1px solid var(--ps-line);
}

.ps-tool__title {
  font-size: var(--ps-text-md);
  font-weight: var(--ps-weight-semibold);
  letter-spacing: 0;
}

.ps-tool__body {
  display: grid;
  gap: var(--ps-space-5);
  padding: var(--ps-space-4);
}

.ps-tool__inputs,
.ps-tool__output {
  display: grid;
  align-content: start;
  gap: var(--ps-space-4);
  min-width: 0;
}

@container ps-tool (min-width: 480px) {
  .ps-tool__head {
    padding-inline: var(--ps-space-5);
  }

  .ps-tool__body {
    padding: var(--ps-space-5);
  }

  .ps-result {
    padding: var(--ps-space-5);
  }
}

@container ps-tool (min-width: 720px) {
  .ps-tool__head {
    padding-inline: var(--ps-space-6);
  }

  .ps-tool__body {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--ps-space-6);
    padding: var(--ps-space-6);
  }

  .ps-tool__output {
    position: sticky;
    top: var(--ps-space-4);
  }

  .ps-tool--wide .ps-tool__body {
    grid-template-columns: minmax(0, 1fr);
  }

  .ps-tool--wide .ps-tool__output {
    position: static;
    justify-self: end;
    width: min(100%, 30rem);
  }
}

/* Forms: a stack of fields; rows put short fields side by side when they fit. */
.ps-form {
  display: grid;
  gap: var(--ps-space-4);
}

.ps-form__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
  gap: var(--ps-space-4);
}

/* A titled group of fields inside a tool (seller, client, terms...). */
.ps-group {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--ps-space-4);
  min-width: 0;
}

.ps-group + .ps-group {
  padding-top: var(--ps-space-5);
  border-top: 1px solid var(--ps-line);
}

.ps-group__title {
  font-size: var(--ps-text-md);
  font-weight: var(--ps-weight-semibold);
  letter-spacing: 0;
}

/* A group folded by default is a native disclosure: keyboard and screen readers
   come with it, and its contents stay in the HTML. */
details.ps-group > summary.ps-group__title {
  cursor: pointer;
}

/* Saving needs the connect flow. With it off the server says so on <main>, so the
   button is gone before first paint and nothing shifts when the engine starts. */
main[data-connect="off"] [data-ps-needs-connect] {
  display: none;
}

/* ==== Field ===============================================================
   label, hint, error, then the control (the order screen readers and the
   on-screen keyboard both want). A div for one control, a fieldset with a
   legend.ps-field__label for a group (segmented, radios, checkboxes). */
.ps-field {
  display: block;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.ps-field > * + * {
  margin-top: 0.375rem;
}

.ps-field__label {
  display: block;
  color: var(--ps-text);
  font-size: var(--ps-text-sm);
  font-weight: var(--ps-weight-semibold);
  line-height: var(--ps-leading-snug);
}

legend.ps-field__label {
  float: left;
  width: 100%;
  margin-bottom: 0.375rem;
}

legend.ps-field__label + * {
  clear: both;
}

.ps-field__optional {
  color: var(--ps-text-muted);
  font-weight: var(--ps-weight-regular);
}

.ps-field__hint {
  color: var(--ps-text-muted);
  font-size: var(--ps-text-sm);
  line-height: var(--ps-leading-snug);
}

.ps-field__error {
  display: flex;
  align-items: flex-start;
  gap: 0.375rem;
  color: var(--ps-danger-text);
  font-size: var(--ps-text-sm);
  font-weight: var(--ps-weight-semibold);
  line-height: var(--ps-leading-snug);
}

.ps-field__error::before {
  content: "";
  flex: none;
  width: 1.125rem;
  height: 1.125rem;
  background-color: currentColor;
  -webkit-mask: var(--ps-i-alert) center / contain no-repeat;
  mask: var(--ps-i-alert) center / contain no-repeat;
}

.ps-field__error:empty {
  display: none;
}

/* ==== Inputs ==============================================================
   Numbers, money and percentages are type="text" inputmode="decimal" (so
   "1 234,56" can be typed in French) with ps-input--numeric. */
.ps-input,
.ps-select,
.ps-textarea {
  display: block;
  width: 100%;
  min-height: var(--ps-control-height);
  padding: 0.5625rem 0.75rem;
  border: 1px solid var(--ps-control-border);
  border-radius: var(--ps-radius-control);
  background-color: var(--ps-input-bg);
  color: var(--ps-text);
  font-size: max(16px, var(--ps-text-md));
  line-height: 1.375;
  -webkit-appearance: none;
  appearance: none;
  transition: border-color var(--ps-duration) var(--ps-ease), box-shadow var(--ps-duration) var(--ps-ease);
}

@media (hover: hover) {
  .ps-input:hover,
  .ps-select:hover,
  .ps-textarea:hover,
  .ps-input-group:hover {
    border-color: var(--ps-control-border-hover);
  }
}

.ps-input[aria-invalid="true"],
.ps-select[aria-invalid="true"],
.ps-textarea[aria-invalid="true"] {
  border-color: var(--ps-danger-border);
  box-shadow: inset 0 0 0 1px var(--ps-danger-border);
}

.ps-input:disabled,
.ps-select:disabled,
.ps-textarea:disabled {
  cursor: not-allowed;
  opacity: 0.55;
}

.ps-input[readonly],
.ps-textarea[readonly] {
  border-color: var(--ps-line-strong);
  background-color: var(--ps-wash);
}

.ps-input--numeric {
  font-variant-numeric: tabular-nums;
}

.ps-input[type="date"],
.ps-input[type="time"] {
  min-width: 0;
}

.ps-input::-webkit-date-and-time-value {
  min-height: 1.375em;
  text-align: start;
}

.ps-input::-webkit-calendar-picker-indicator {
  cursor: pointer;
}

.ps-select {
  padding-right: 2.5rem;
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right 1.0625rem center, right 0.75rem center;
  background-size: 0.3125rem 0.3125rem;
  background-repeat: no-repeat;
  text-overflow: ellipsis;
  cursor: pointer;
}

.ps-textarea {
  min-height: 6.5rem;
  line-height: var(--ps-leading-snug);
  resize: vertical;
}

/* Prefix/suffix unit (EUR, %, h, days) inside the input's box. */
.ps-input-group {
  display: flex;
  align-items: stretch;
  width: 100%;
  min-height: var(--ps-control-height);
  border: 1px solid var(--ps-control-border);
  border-radius: var(--ps-radius-control);
  background-color: var(--ps-input-bg);
  color: var(--ps-text);
  transition: border-color var(--ps-duration) var(--ps-ease), box-shadow var(--ps-duration) var(--ps-ease);
}

.ps-input-group:focus-within {
  outline: var(--ps-focus-width) solid var(--ps-focus);
  outline-offset: var(--ps-focus-offset);
}

.ps-input-group:has([aria-invalid="true"]) {
  border-color: var(--ps-danger-border);
  box-shadow: inset 0 0 0 1px var(--ps-danger-border);
}

.ps-input-group > .ps-input {
  flex: 1 1 auto;
  width: auto;
  min-width: 0;
  min-height: calc(var(--ps-control-height) - 2px);
  border: 0;
  border-radius: inherit;
  background-color: transparent;
  box-shadow: none;
}

.ps-input-group > .ps-input:focus-visible {
  outline: none;
}

.ps-input-group__unit {
  display: flex;
  flex: none;
  align-items: center;
  padding-inline: 0.75rem;
  color: var(--ps-text-muted);
  white-space: nowrap;
  -webkit-user-select: none;
  user-select: none;
}

.ps-input-group__unit:first-child {
  padding-right: 0;
}

.ps-input-group__unit:last-child {
  padding-left: 0;
}

/* ==== Segmented control ===================================================
   Native radios (arrow keys work) drawn as segments. Up to about 5 short
   options; use a select beyond. */
.ps-segmented {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  padding: 3px;
  border: 1px solid var(--ps-control-border);
  border-radius: var(--ps-radius-control);
  background-color: var(--ps-wash);
  color: var(--ps-text);
}

.ps-segmented__option {
  position: relative;
  display: flex;
  flex: 1 1 auto;
  min-width: 0;
}

.ps-segmented__input {
  position: absolute;
  top: -3px;
  left: 0;
  z-index: var(--ps-z-raised);
  width: 100%;
  height: calc(100% + 6px);
  margin: 0;
  cursor: pointer;
  opacity: 0;
}

.ps-segmented__label {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  justify-content: center;
  min-height: 2.5rem;
  padding: 0.375rem 0.5rem;
  border-radius: calc(var(--ps-radius-control) - 3px);
  font-size: var(--ps-text-sm);
  font-weight: var(--ps-weight-semibold);
  line-height: 1.25;
  text-align: center;
  font-variant-numeric: tabular-nums;
  transition: background-color var(--ps-duration) var(--ps-ease), color var(--ps-duration) var(--ps-ease);
}

@media (hover: hover) {
  .ps-segmented__input:hover + .ps-segmented__label {
    background-color: var(--ps-soft);
  }
}

.ps-segmented__input:checked + .ps-segmented__label {
  background-color: var(--ps-primary);
  color: var(--ps-on-primary);
  box-shadow: var(--ps-shadow-sm);
}

.ps-segmented__input:focus-visible + .ps-segmented__label {
  outline: var(--ps-focus-width) solid var(--ps-focus);
  outline-offset: 1px;
}

.ps-segmented__input:disabled {
  cursor: not-allowed;
}

.ps-segmented__input:disabled + .ps-segmented__label {
  opacity: 0.55;
}

/* ==== Toggle ==============================================================
   A checkbox with role="switch": on/off settings that apply at once. */
.ps-toggle {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--ps-space-3);
  min-height: var(--ps-target);
  cursor: pointer;
}

.ps-toggle__input {
  position: absolute;
  top: 0;
  left: 0;
  z-index: var(--ps-z-raised);
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;
  opacity: 0;
}

.ps-toggle__track {
  position: relative;
  flex: none;
  width: 2.75rem;
  height: 1.5rem;
  border-radius: var(--ps-radius-pill);
  background-color: var(--ps-control-border);
  transition: background-color var(--ps-duration) var(--ps-ease);
}

.ps-toggle__track::before {
  content: "";
  position: absolute;
  top: 0.1875rem;
  left: 0.1875rem;
  width: 1.125rem;
  height: 1.125rem;
  border-radius: 50%;
  background-color: var(--ps-knob);
  box-shadow: var(--ps-shadow-sm);
  transition: transform var(--ps-duration) var(--ps-ease);
}

.ps-toggle__input:checked + .ps-toggle__track {
  background-color: var(--ps-primary);
}

.ps-toggle__input:checked + .ps-toggle__track::before {
  transform: translateX(1.25rem);
}

.ps-toggle__input:focus-visible + .ps-toggle__track {
  outline: var(--ps-focus-width) solid var(--ps-focus);
  outline-offset: var(--ps-focus-offset);
}

.ps-toggle__input:disabled + .ps-toggle__track,
.ps-toggle__input:disabled ~ .ps-toggle__label {
  opacity: 0.55;
}

.ps-toggle__label {
  line-height: var(--ps-leading-snug);
}

/* ==== Checkbox (and radio) ================================================ */
.ps-check {
  display: flex;
  align-items: flex-start;
  gap: var(--ps-space-3);
  min-height: var(--ps-target);
  padding-block: 0.6875rem;
  line-height: var(--ps-leading-snug);
  cursor: pointer;
}

.ps-check__input {
  flex: none;
  width: 1.25rem;
  height: 1.25rem;
  margin: 0;
  accent-color: var(--ps-primary);
  cursor: pointer;
}

.ps-check__hint {
  display: block;
  color: var(--ps-text-muted);
  font-size: var(--ps-text-sm);
}

.ps-check__input:disabled,
.ps-check__input:disabled ~ * {
  cursor: not-allowed;
  opacity: 0.55;
}

/* ==== Buttons =============================================================
   .ps-btn alone is the secondary button. States on any button through
   data-state: idle (default) | working | done | error; the engine also
   changes the label ("Saving...", "Saved") and sets aria-disabled while
   working. */
.ps-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--ps-space-2);
  min-height: var(--ps-control-height);
  padding: 0.5rem 1.125rem;
  border: 1px solid var(--ps-line-strong);
  border-radius: var(--ps-radius-control);
  background-color: var(--ps-surface);
  color: var(--ps-text);
  font-size: 0.9375rem;
  font-weight: var(--ps-weight-semibold);
  line-height: 1.25;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  -webkit-user-select: none;
  user-select: none;
  transition:
    background-color var(--ps-duration) var(--ps-ease),
    border-color var(--ps-duration) var(--ps-ease),
    color var(--ps-duration) var(--ps-ease);
}

.ps-btn--secondary {
  border-color: var(--ps-line-strong);
  background-color: var(--ps-surface);
  color: var(--ps-text);
}

.ps-btn--primary {
  border-color: transparent;
  background-color: var(--ps-primary);
  color: var(--ps-on-primary);
}

.ps-btn--ghost {
  border-color: transparent;
  background-color: transparent;
  color: var(--ps-link);
}

.ps-btn--danger {
  border-color: transparent;
  background-color: var(--ps-danger);
  color: var(--ps-on-danger);
}

@media (hover: hover) {
  .ps-btn:hover {
    border-color: var(--ps-control-border);
    background-color: var(--ps-wash);
    color: var(--ps-text);
  }

  .ps-btn--primary:hover {
    border-color: transparent;
    background-color: var(--ps-primary-hover);
    color: var(--ps-on-primary);
  }

  .ps-btn--ghost:hover {
    border-color: transparent;
    background-color: var(--ps-soft);
    color: var(--ps-link-hover);
  }

  .ps-btn--danger:hover {
    border-color: transparent;
    background-color: var(--ps-danger-hover);
    color: var(--ps-on-danger);
  }
}

.ps-btn--small {
  gap: 0.375rem;
  min-height: var(--ps-control-height-sm);
  padding: 0.375rem 0.75rem;
  font-size: var(--ps-text-sm);
}

.ps-btn--icon {
  width: var(--ps-control-height);
  padding: 0;
}

.ps-btn--icon.ps-btn--small {
  width: var(--ps-control-height-sm);
}

@media (pointer: coarse) {
  .ps-btn--small {
    min-height: var(--ps-target);
  }

  .ps-btn--icon.ps-btn--small {
    width: var(--ps-target);
  }
}

.ps-btn--block {
  display: flex;
  width: 100%;
}

.ps-btn .ps-icon {
  width: 1.125rem;
  height: 1.125rem;
}

.ps-btn--icon .ps-icon {
  width: 1.25rem;
  height: 1.25rem;
}

.ps-btn:disabled,
.ps-btn[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: 0.55;
  pointer-events: none;
}

.ps-btn[data-state="working"] {
  cursor: progress;
  opacity: 0.8;
}

.ps-btn[data-state="working"] .ps-icon {
  --ps-icon: var(--ps-i-clock);
}

.ps-btn[data-state="done"] .ps-icon {
  --ps-icon: var(--ps-i-check);
}

.ps-btn[data-state="error"] .ps-icon {
  --ps-icon: var(--ps-i-alert);
}

.ps-btn[data-state="done"]:not(.ps-btn--primary, .ps-btn--danger) {
  border-color: var(--ps-success-border);
  color: var(--ps-success-text);
}

.ps-btn[data-state="error"]:not(.ps-btn--primary, .ps-btn--danger) {
  border-color: var(--ps-danger-border);
  color: var(--ps-danger-text);
}

.ps-btn--primary[data-state="error"] {
  background-color: var(--ps-danger);
  color: var(--ps-on-danger);
}

/* ==== Result panel ========================================================
   Big figure, breakdown rows, formula line. Put aria-live="polite" and
   aria-atomic="true" on .ps-result__summary, not on the whole panel. */
.ps-result {
  display: grid;
  gap: var(--ps-space-3);
  padding: var(--ps-space-4);
  border: 1px solid var(--ps-line);
  border-radius: var(--ps-radius-panel);
  background-color: var(--ps-wash);
  color: var(--ps-text);
}

.ps-result__summary {
  display: grid;
  gap: var(--ps-space-1);
}

.ps-result__label {
  color: var(--ps-text-muted);
  font-size: var(--ps-text-sm);
  font-weight: var(--ps-weight-semibold);
}

.ps-result__figure {
  color: var(--ps-text);
  font-size: var(--ps-text-figure);
  font-weight: var(--ps-weight-bold);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--ps-tracking-tight);
  line-height: 1.1;
  overflow-wrap: anywhere;
}

.ps-result__unit {
  margin-left: 0.15em;
  color: var(--ps-text-muted);
  font-size: 0.6em;
  font-weight: var(--ps-weight-semibold);
  letter-spacing: 0;
}

.ps-result__note {
  color: var(--ps-text-muted);
  font-size: var(--ps-text-sm);
}

.ps-result__rows {
  margin: 0;
  border-top: 1px solid var(--ps-line);
}

.ps-result__row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0 var(--ps-space-3);
  padding-block: var(--ps-space-2);
  border-bottom: 1px solid var(--ps-line);
}

.ps-result__term {
  color: var(--ps-text-muted);
  font-size: var(--ps-text-sm);
}

.ps-result__value {
  margin: 0;
  font-weight: var(--ps-weight-semibold);
  font-variant-numeric: tabular-nums;
  text-align: end;
}

.ps-result__row--total {
  border-bottom: 0;
}

.ps-result__row--total .ps-result__term {
  color: var(--ps-text);
  font-size: var(--ps-text-md);
  font-weight: var(--ps-weight-semibold);
}

.ps-result__row--total .ps-result__value {
  font-size: var(--ps-text-lg);
  font-weight: var(--ps-weight-bold);
}

.ps-result[data-state="empty"] .ps-result__figure,
.ps-result[data-state="empty"] .ps-result__value {
  color: var(--ps-text-muted);
}

/* The formula line, in the result panel or in the content. */
.ps-formula {
  display: block;
  margin: 0;
  padding: var(--ps-space-2) var(--ps-space-3);
  border: 1px solid var(--ps-line);
  border-left: 3px solid var(--ps-accent);
  border-radius: var(--ps-radius-sm);
  background-color: var(--ps-surface);
  color: var(--ps-text);
  font-family: var(--ps-font-mono);
  font-size: var(--ps-text-sm);
  line-height: var(--ps-leading-snug);
  overflow-wrap: anywhere;
  white-space: pre-line; /* the handlers write one step of the working per line */
}

/* ==== Actions bar =========================================================
   Copy / Export / Save to Priostack under the result, then a status line
   (role="status") that collapses when empty. */
.ps-actions__buttons {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ps-space-2);
}

.ps-actions__buttons > .ps-btn {
  flex: 1 1 auto;
}

.ps-actions__status {
  color: var(--ps-text-muted);
  font-size: var(--ps-text-sm);
  line-height: var(--ps-leading-snug);
}

.ps-actions__status:not(:empty) {
  margin-top: var(--ps-space-2);
}

.ps-actions__status[data-state="done"] {
  color: var(--ps-success-text);
}

.ps-actions__status[data-state="error"] {
  color: var(--ps-danger-text);
}

/* ==== Editable rows =======================================================
   Timesheet and invoice lines: a real table from 900px of width, one card
   per row below. Every cell carries its own label (visible on cards,
   visually hidden in the table), so inputs are always labelled. */
.ps-rows {
  container: ps-rows / inline-size;
}

/* How tall a row is: a timesheet's card, measured, and its true height in the
   table. tests/browser/timesheet.test.mjs holds both to what a row really takes. */
.ps-rows__table,
[data-ps-kept-rows] {
  --ps-row-height: 34.5rem;
}

@container ps-rows (min-width: 900px) {
  .ps-rows__table,
  [data-ps-kept-rows] {
    --ps-row-height: calc(var(--ps-control-height) + 2 * var(--ps-space-2) + 1px);
  }
}

.ps-rows__table {
  display: block;
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
}

.ps-rows__table > thead {
  display: none;
}

.ps-rows__table > tbody,
.ps-rows__table > tfoot {
  display: grid;
  gap: var(--ps-space-3);
}

.ps-rows__table > tfoot {
  margin-top: var(--ps-space-3);
}

.ps-rows__row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--ps-space-3);
  padding: var(--ps-space-3) var(--ps-space-4) var(--ps-space-4);
  border: 1px solid var(--ps-line);
  border-radius: var(--ps-radius-panel);
  background-color: var(--ps-surface);
  color: var(--ps-text);
}

.ps-rows__index {
  grid-row: 1;
  grid-column: 1;
  align-self: center;
  color: var(--ps-text-muted);
  font-size: var(--ps-text-sm);
  font-weight: var(--ps-weight-semibold);
  font-variant-numeric: tabular-nums;
}

.ps-rows__cell {
  display: block;
  min-width: 0;
  padding: 0;
}

.ps-rows__cell--wide {
  grid-column: 1 / -1;
}

.ps-rows__cell--action {
  grid-row: 1;
  grid-column: 2;
  align-self: center;
  justify-self: end;
}

/* A note in a row starts on one line, like its neighbours, and grows on request. */
.ps-rows__cell .ps-textarea {
  min-height: var(--ps-control-height);
}

.ps-rows__label {
  display: block;
  margin-bottom: 0.375rem;
  font-size: var(--ps-text-sm);
  font-weight: var(--ps-weight-semibold);
  line-height: var(--ps-leading-snug);
}

.ps-toggle .ps-rows__label,
.ps-check .ps-rows__label {
  margin-bottom: 0;
  font-weight: var(--ps-weight-regular);
}

/* An amount wider than its cell goes on to a second line. Cut, or run over its
   neighbour, it would read as another amount. */
.ps-rows__value {
  display: flex;
  align-items: center;
  min-height: var(--ps-control-height);
  font-weight: var(--ps-weight-semibold);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.ps-rows__total {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--ps-space-2);
  padding: var(--ps-space-3) var(--ps-space-4);
  border-radius: var(--ps-radius-panel);
  background-color: var(--ps-wash);
  color: var(--ps-text);
  font-weight: var(--ps-weight-bold);
}

.ps-rows__total > * {
  display: block;
  padding: 0;
  font-variant-numeric: tabular-nums;
}

.ps-rows__total > :empty {
  display: none;
}

.ps-rows__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--ps-space-2) var(--ps-space-3);
  margin-top: var(--ps-space-3);
}

@container ps-rows (min-width: 900px) {
  .ps-rows__table {
    display: table;
    table-layout: fixed;
    border: 1px solid var(--ps-line);
    border-radius: var(--ps-radius-panel);
    background-color: var(--ps-surface);
  }

  .ps-rows__table > thead { display: table-header-group; }
  .ps-rows__table > tbody { display: table-row-group; }
  .ps-rows__table > tfoot { display: table-footer-group; }

  .ps-rows__row,
  .ps-rows__total {
    display: table-row;
    padding: 0;
    border: 0;
    border-radius: 0;
    background-color: transparent;
  }

  .ps-rows__table > * > tr > th,
  .ps-rows__table > * > tr > td {
    display: table-cell;
    padding: var(--ps-space-2) var(--ps-space-1);
    border-bottom: 1px solid var(--ps-line);
    vertical-align: middle;
  }

  .ps-rows__table > * > tr > :first-child {
    padding-left: var(--ps-space-2);
  }

  .ps-rows__table > * > tr > :last-child {
    padding-right: var(--ps-space-2);
  }

  /* A long sheet arrives in chunks below the fold: a cell nobody can see yet is
     neither styled, laid out nor painted. The focus ring reaches past the cell,
     hence the clip margin. Such a cell has no height of its own to give, so the
     row header holds the row's, or the row would change height as it comes into
     view and take everything under it along. */
  .ps-rows__table > tbody > tr > td {
    content-visibility: auto;
    overflow-clip-margin: var(--ps-space-2);
  }

  .ps-rows__table > tbody > tr > th {
    height: var(--ps-row-height);
  }

  /* An error is a sentence and a cell a few words wide. So it runs on under its
     neighbours, whose controls stay at the top of the row, and only keeps to its
     cell when the next one has something to say too. Nothing clips such a row. */
  .ps-rows__row:has(.ps-field__error:not(:empty)) > * {
    content-visibility: visible;
    vertical-align: top;
  }

  .ps-rows__cell > .ps-field__error {
    width: max-content;
    max-width: 20rem;
  }

  .ps-rows__cell:has(+ .ps-rows__cell > .ps-field__error:not(:empty)) > .ps-field__error {
    width: auto;
  }

  .ps-rows__table .ps-input,
  .ps-rows__table .ps-textarea {
    padding-inline: 0.5rem;
  }

  .ps-rows__table .ps-select {
    padding-left: 0.5rem;
  }

  .ps-rows__table > thead > tr > th {
    background-color: var(--ps-wash);
    color: var(--ps-text-muted);
    font-size: var(--ps-text-xs);
    font-weight: var(--ps-weight-semibold);
  }

  .ps-rows__table > thead > tr > th:first-child {
    border-top-left-radius: calc(var(--ps-radius-panel) - 1px);
  }

  .ps-rows__table > thead > tr > th:last-child {
    border-top-right-radius: calc(var(--ps-radius-panel) - 1px);
  }

  .ps-rows__table > tbody:last-child > tr:last-child > * {
    border-bottom: 0;
  }

  .ps-rows__label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .ps-rows__index {
    text-align: center;
  }

  .ps-rows__num,
  .ps-rows__cell--num,
  .ps-rows__cell--num .ps-input {
    text-align: end;
  }

  .ps-rows__cell--num .ps-rows__value {
    justify-content: flex-end;
  }

  .ps-rows__cell--action {
    text-align: end;
  }

  .ps-rows__total > th,
  .ps-rows__total > td {
    border-bottom: 0;
    background-color: var(--ps-wash);
  }

  .ps-rows__total > :empty {
    display: table-cell;
  }

  .ps-rows__total > :first-child {
    border-bottom-left-radius: calc(var(--ps-radius-panel) - 1px);
    text-align: end;
  }

  .ps-rows__total > :last-child {
    border-bottom-right-radius: calc(var(--ps-radius-panel) - 1px);
  }
}

/* Column widths for the table layout, on the thead cells, named by what the
   column holds; the one column without a width (description, client) takes
   the rest. Keep the fixed columns under about 750px. */
.ps-rows__th--index { width: 2.5rem; }
.ps-rows__th--short { width: 5.5rem; }   /* integer, percent, boolean, short number */
.ps-rows__th--time { width: 7rem; }      /* time, duration */
.ps-rows__th--money { width: 8.5rem; }   /* money, decimal number */
.ps-rows__th--date { width: 9.5rem; }    /* date */
.ps-rows__th--action { width: 3.75rem; } /* the remove button */

/* The rows of a kept list are on the device, so the server cannot draw them. A
   script in the head says how many there are before first paint, and their
   room is taken before they arrive: what sits under the list stays put. The note
   of an empty result folds too: with rows on the way the result will not stay
   empty, and its going would move what is under it. Folds, and is not removed:
   an empty note on a live card still keeps its gap in the summary. */
:root {
  --ps-rows-kept: 0;
}

[data-ps-kept-rows] {
  --ps-rows-head: 0rem;
}

:root[data-ps-kept] [data-ps-kept-rows] {
  min-height: calc(var(--ps-rows-kept) * var(--ps-row-height) + var(--ps-rows-head));
}

:root[data-ps-kept] [data-ps-kept-rows] > .ps-empty {
  visibility: hidden;
}

:root[data-ps-kept] .ps-result[data-state="empty"] .ps-result__note {
  height: 0;
  overflow: hidden;
}

@container ps-rows (min-width: 900px) {
  [data-ps-kept-rows] {
    --ps-rows-head: 3.75rem;
  }
}

/* ==== Read-only table (totals per VAT rate, per client...) ================ */
.ps-table-wrap {
  overflow-x: auto;
  border: 1px solid var(--ps-line);
  border-radius: var(--ps-radius-panel);
}

.ps-table {
  width: 100%;
  font-size: var(--ps-text-sm);
  font-variant-numeric: tabular-nums;
}

.ps-table > caption {
  padding: var(--ps-space-2) var(--ps-space-3);
  color: var(--ps-text-muted);
  font-size: var(--ps-text-sm);
  text-align: start;
}

.ps-table th,
.ps-table td {
  padding: 0.625rem var(--ps-space-3);
  border-bottom: 1px solid var(--ps-line);
  text-align: start;
  vertical-align: top;
}

.ps-table > thead th {
  background-color: var(--ps-wash);
  color: var(--ps-text-muted);
  font-size: var(--ps-text-xs);
  font-weight: var(--ps-weight-semibold);
  white-space: nowrap;
}

.ps-table > tbody > tr:last-child > * {
  border-bottom: 0;
}

.ps-table > tfoot th,
.ps-table > tfoot td {
  border-top: 1px solid var(--ps-line-strong);
  border-bottom: 0;
  font-weight: var(--ps-weight-bold);
}

.ps-table .ps-table__num {
  text-align: end;
  white-space: nowrap;
}

/* ==== App page layout ====================================================
   The tool, then a side column (related apps, then the house ad), then the
   explanations. One column on small widths, in that order. From a 1200px
   viewport the side column sits beside the tool, so the related apps are seen
   without scrolling; below that the tool needs the width for its own two
   columns (container 720px). */
.ps-app-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}

.ps-app-layout__tool,
.ps-app-layout__content {
  min-width: 0;
}

.ps-app-layout__side {
  display: grid;
  align-content: start;
  gap: var(--ps-space-6);
  min-width: 0;
  margin-top: var(--ps-space-6);
}

.ps-app-layout__side > .ps-related,
.ps-app-layout__side > .ps-promo {
  margin-top: 0;
}

@media (min-width: 1200px) {
  .ps-app-layout {
    grid-template-columns: minmax(0, 1fr) 20rem;
    grid-template-areas:
      "tool side"
      "content side";
    align-items: start;
    column-gap: var(--ps-space-6);
  }

  .ps-app-layout__tool {
    grid-area: tool;
  }

  .ps-app-layout__side {
    grid-area: side;
    gap: var(--ps-space-5);
    margin-top: 0;
  }

  .ps-app-layout__content {
    grid-area: content;
  }

  .ps-app-layout__side .ps-related {
    gap: var(--ps-space-3);
  }

  .ps-app-layout__side .ps-related__title {
    font-size: var(--ps-text-lg);
  }

  .ps-app-layout__side .ps-app-card__text {
    display: -webkit-box;
    overflow: hidden;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
  }
}

/* ==== House ad: one Priostack product per page (internal/pages/promos.go) === */
.ps-promo {
  display: grid;
  justify-items: start;
  gap: var(--ps-space-2);
  margin-top: var(--ps-space-6);
  padding: var(--ps-space-5);
  border: 1px solid var(--ps-line);
  border-inline-start: 4px solid var(--ps-accent);
  border-radius: var(--ps-radius-card);
  background-color: var(--ps-surface);
  color: var(--ps-text);
}

.ps-promo__label {
  margin: 0;
  font-size: var(--ps-text-xs);
  font-weight: 600;
  color: var(--ps-text-muted);
}

.ps-promo__title {
  margin: 0;
  font-size: var(--ps-text-lg);
}

.ps-promo__text {
  max-width: 65ch;
  margin: 0;
}

.ps-promo__cta {
  margin-top: var(--ps-space-2);
}

.ps-promo__note {
  font-size: var(--ps-text-sm);
  color: var(--ps-text-muted);
}

/* ==== Related apps and app cards ========================================== */
.ps-related {
  display: grid;
  gap: var(--ps-space-4);
  margin-top: var(--ps-space-7);
}

.ps-related__title {
  font-size: var(--ps-text-xl);
}

/* The way from the related apps to the rest of their category on the hub. */
.ps-related__more {
  margin: 0;
}

.ps-related__more-link {
  font-weight: var(--ps-weight-semibold);
}

/* ==== Hub: categories and subcategories ===================================
   A row of category links under the page head, each with its count, then one
   section per category with a heading per subcategory and its cards (h4). */
.ps-category-nav__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ps-space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.ps-category-nav__link {
  display: inline-flex;
  align-items: center;
  gap: var(--ps-space-2);
  min-height: var(--ps-target);
  padding: 0 var(--ps-space-3) 0 var(--ps-space-4);
  border: 1px solid var(--ps-line);
  border-radius: var(--ps-radius-pill);
  background-color: var(--ps-surface);
  color: var(--ps-text);
  font-weight: var(--ps-weight-medium);
  text-decoration: none;
  transition: border-color var(--ps-duration) var(--ps-ease), color var(--ps-duration) var(--ps-ease);
}

.ps-category-nav__count {
  padding: 0.125rem 0.5rem;
  border-radius: var(--ps-radius-pill);
  background-color: var(--ps-soft);
  color: var(--ps-link-hover);
  font-size: var(--ps-text-xs);
  font-weight: var(--ps-weight-semibold);
  line-height: 1.5;
}

@media (hover: hover) {
  .ps-category-nav__link:hover {
    border-color: var(--ps-line-strong);
    color: var(--ps-link);
  }
}

/* The hub in two columns from a 1200px viewport: the category links and the
   list on the left; on the right the featured apps, then the house ad under
   them. The rows are auto auto 1fr so that the list's height goes to the last
   row only: the list starts under the links, the ad under the featured apps.
   In one column the order is the source's: links, featured, list, ad. */
.ps-hub-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}

.ps-hub-layout__nav,
.ps-hub-layout__list {
  min-width: 0;
}

.ps-featured {
  display: grid;
  align-content: start;
  gap: var(--ps-space-3);
  min-width: 0;
  margin-top: var(--ps-space-6);
}

.ps-featured__title {
  font-size: var(--ps-text-lg);
}

.ps-featured .ps-cards {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
  gap: var(--ps-space-2);
}

.ps-featured .ps-app-card {
  align-items: center;
  padding-block: var(--ps-space-3);
}

.ps-featured .ps-app-card__icon {
  grid-row: auto;
}

.ps-featured .ps-app-card::after {
  top: 50%;
  margin-top: -0.5625rem;
}

@media (min-width: 1200px) {
  .ps-hub-layout {
    grid-template-columns: minmax(0, 1fr) 20rem;
    grid-template-rows: auto auto 1fr;
    align-items: start;
    column-gap: var(--ps-space-6);
  }

  .ps-hub-layout__nav {
    grid-column: 1;
    grid-row: 1;
  }

  .ps-hub-layout__list {
    grid-column: 1;
    grid-row: 2 / 4;
  }

  .ps-featured {
    grid-column: 2;
    grid-row: 1 / 3;
    margin-top: 0;
  }

  .ps-hub-layout > .ps-promo {
    grid-column: 2;
    grid-row: 3;
    margin-top: var(--ps-space-5);
  }
}

.ps-category {
  display: grid;
  gap: var(--ps-space-4);
  margin-top: var(--ps-space-7);
  scroll-margin-top: var(--ps-space-4);
}

.ps-category__title {
  font-size: var(--ps-text-2xl);
}

.ps-category__text {
  max-width: var(--ps-container-prose);
  margin: calc(-1 * var(--ps-space-2)) 0 0;
  color: var(--ps-text-muted);
}

.ps-category__group {
  display: grid;
  gap: var(--ps-space-3);
  margin-top: var(--ps-space-2);
}

.ps-category__group-title {
  font-size: var(--ps-text-lg);
  scroll-margin-top: var(--ps-space-4);
}

/* ==== Site map page ======================================================= */
.ps-sitemap {
  display: grid;
  gap: var(--ps-space-6);
}

@media (min-width: 900px) {
  .ps-sitemap {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.ps-sitemap__section {
  display: grid;
  align-content: start;
  gap: var(--ps-space-2);
}

.ps-sitemap__title {
  font-size: var(--ps-text-xl);
}

.ps-sitemap__subtitle {
  margin-top: var(--ps-space-2);
  color: var(--ps-text-muted);
  font-size: var(--ps-text-md);
  font-weight: var(--ps-weight-semibold);
}

.ps-sitemap__list {
  display: grid;
  gap: var(--ps-space-1);
  margin: 0;
  padding-inline-start: var(--ps-space-5);
}

.ps-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: var(--ps-space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.ps-app-card {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-content: start;
  gap: var(--ps-space-1) var(--ps-space-3);
  padding: var(--ps-space-4) 2.75rem var(--ps-space-4) var(--ps-space-4);
  border: 1px solid var(--ps-line);
  border-radius: var(--ps-radius-card);
  background-color: var(--ps-surface);
  color: var(--ps-text);
  transition: border-color var(--ps-duration) var(--ps-ease), box-shadow var(--ps-duration) var(--ps-ease);
}

.ps-app-card::after {
  content: "";
  position: absolute;
  top: 1.125rem;
  right: var(--ps-space-4);
  width: 1.125rem;
  height: 1.125rem;
  color: var(--ps-text-muted);
  background-color: currentColor;
  -webkit-mask: var(--ps-i-arrow-right) center / contain no-repeat;
  mask: var(--ps-i-arrow-right) center / contain no-repeat;
  transition: transform var(--ps-duration) var(--ps-ease);
}

.ps-app-card__icon {
  display: grid;
  grid-row: 1 / span 2;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 10px;
  background-color: var(--ps-soft);
  color: var(--ps-link);
  font-weight: var(--ps-weight-bold);
}

.ps-app-card__icon .ps-icon {
  width: 1.25rem;
  height: 1.25rem;
}

.ps-app-card__icon--orange {
  background-color: var(--ps-warning-bg);
  color: var(--ps-accent-text);
}

.ps-app-card__icon--green {
  background-color: var(--ps-success-bg);
  color: var(--ps-success-text);
}

.ps-app-card__title {
  margin: 0;
  font-size: var(--ps-text-md);
  font-weight: var(--ps-weight-semibold);
  letter-spacing: -0.01em;
  line-height: var(--ps-leading-snug);
}

.ps-app-card__link {
  color: var(--ps-text);
  text-decoration: none;
}

.ps-app-card__link::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: var(--ps-z-raised);
}

.ps-app-card__link:focus-visible {
  outline: none;
}

.ps-app-card:focus-within {
  outline: var(--ps-focus-width) solid var(--ps-focus);
  outline-offset: var(--ps-focus-offset);
}

.ps-app-card__text {
  grid-column: 2;
  color: var(--ps-text-muted);
  font-size: var(--ps-text-sm);
  line-height: var(--ps-leading-snug);
}

@media (hover: hover) {
  .ps-app-card:hover {
    border-color: var(--ps-line-strong);
    box-shadow: var(--ps-shadow-md);
  }

  .ps-app-card:hover .ps-app-card__link {
    color: var(--ps-link);
    text-decoration: underline;
  }

  .ps-app-card:hover::after {
    color: var(--ps-link);
    transform: translateX(2px);
  }
}

/* ==== FAQ ================================================================= */
.ps-faq {
  border-top: 1px solid var(--ps-line);
}

.ps-faq__item {
  border-bottom: 1px solid var(--ps-line);
}

.ps-faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ps-space-4);
  min-height: var(--ps-target);
  padding-block: var(--ps-space-3);
  color: var(--ps-text);
  font-weight: var(--ps-weight-semibold);
  line-height: var(--ps-leading-snug);
  list-style: none;
  cursor: pointer;
}

.ps-faq__q::-webkit-details-marker {
  display: none;
}

.ps-faq__q::after {
  content: "";
  flex: none;
  width: 1.25rem;
  height: 1.25rem;
  color: var(--ps-link);
  background-color: currentColor;
  -webkit-mask: var(--ps-i-plus) center / contain no-repeat;
  mask: var(--ps-i-plus) center / contain no-repeat;
}

.ps-faq__item[open] > .ps-faq__q::after {
  -webkit-mask-image: var(--ps-i-minus);
  mask-image: var(--ps-i-minus);
}

@media (hover: hover) {
  .ps-faq__q:hover {
    color: var(--ps-link);
  }
}

.ps-faq__a {
  max-width: var(--ps-container-prose);
  padding-bottom: var(--ps-space-4);
}

.ps-faq__a > * + * {
  margin-top: var(--ps-space-3);
}

/* ==== Notice ============================================================== */
.ps-notice {
  --ps-icon: var(--ps-i-info);
  position: relative;
  padding: var(--ps-space-3) var(--ps-space-4) var(--ps-space-3) 3rem;
  border-radius: var(--ps-radius-panel);
  background-color: var(--ps-info-bg);
  color: var(--ps-text);
  font-size: var(--ps-text-sm);
  line-height: 1.5;
}

.ps-notice::before {
  content: "";
  position: absolute;
  top: calc(var(--ps-space-3) + 0.0625rem);
  left: var(--ps-space-4);
  width: 1.25rem;
  height: 1.25rem;
  color: var(--ps-info-border);
  background-color: currentColor;
  -webkit-mask: var(--ps-icon) center / contain no-repeat;
  mask: var(--ps-icon) center / contain no-repeat;
}

.ps-notice > * + * {
  margin-top: var(--ps-space-1);
}

.ps-notice__title {
  color: var(--ps-info-text);
  font-size: var(--ps-text-sm);
  font-weight: var(--ps-weight-semibold);
  letter-spacing: 0;
}

.ps-notice--info {
  --ps-icon: var(--ps-i-info);
}

.ps-notice--warning {
  --ps-icon: var(--ps-i-warning);
  background-color: var(--ps-warning-bg);
}

.ps-notice--warning::before {
  color: var(--ps-warning-border);
}

.ps-notice--warning .ps-notice__title {
  color: var(--ps-warning-text);
}

.ps-notice--success {
  --ps-icon: var(--ps-i-success);
  background-color: var(--ps-success-bg);
}

.ps-notice--success::before {
  color: var(--ps-success-border);
}

.ps-notice--success .ps-notice__title {
  color: var(--ps-success-text);
}

.ps-notice--danger {
  --ps-icon: var(--ps-i-alert);
  background-color: var(--ps-danger-bg);
}

.ps-notice--danger::before {
  color: var(--ps-danger-border);
}

.ps-notice--danger .ps-notice__title {
  color: var(--ps-danger-text);
}

/* ==== Dialog ==============================================================
   A native <dialog> opened with showModal(): the focus trap, Escape and the top
   layer are the browser's. No display here: the closed state is the browser's
   too. A heading first, then what it is about, then .ps-actions. */
.ps-dialog {
  width: min(32rem, calc(100vw - 2 * var(--ps-gutter)));
  padding: var(--ps-space-5);
  border: 1px solid var(--ps-line);
  border-radius: var(--ps-radius-card);
  background-color: var(--ps-surface);
  color: var(--ps-text);
}

.ps-dialog::backdrop {
  background-color: var(--ps-backdrop);
}

.ps-dialog__title {
  font-size: var(--ps-text-md);
  font-weight: var(--ps-weight-semibold);
}

.ps-dialog__text {
  margin-top: var(--ps-space-3);
  color: var(--ps-text-muted);
}

.ps-dialog > .ps-actions {
  margin-top: var(--ps-space-5);
}

/* ==== Toast ===============================================================
   One per page, a direct child of body, role="status". Shown while it has
   text; the engine clears the text to hide it. */
.ps-toast {
  position: fixed;
  z-index: var(--ps-z-toast);
  bottom: calc(var(--ps-space-4) + env(safe-area-inset-bottom, 0px));
  left: 50%;
  display: flex;
  align-items: center;
  gap: var(--ps-space-2);
  width: max-content;
  max-width: calc(100vw - 2 * var(--ps-gutter));
  padding: var(--ps-space-3) var(--ps-space-4);
  border-radius: var(--ps-radius-panel);
  background-color: var(--ps-toast-bg);
  color: var(--ps-toast-text);
  font-size: var(--ps-text-sm);
  font-weight: var(--ps-weight-medium);
  line-height: var(--ps-leading-snug);
  box-shadow: var(--ps-shadow-lg);
  transform: translateX(-50%);
  transition: opacity var(--ps-duration) var(--ps-ease);
}

.ps-toast:empty {
  padding: 0;
  box-shadow: none;
  opacity: 0;
  pointer-events: none;
}

.ps-toast--success {
  --ps-icon: var(--ps-i-success);
}

.ps-toast--error {
  --ps-icon: var(--ps-i-alert);
}

.ps-toast--success::before,
.ps-toast--error::before {
  content: "";
  flex: none;
  width: 1.125rem;
  height: 1.125rem;
  background-color: currentColor;
  -webkit-mask: var(--ps-icon) center / contain no-repeat;
  mask: var(--ps-icon) center / contain no-repeat;
}

.ps-toast:empty::before {
  display: none;
}

/* ==== Empty state ========================================================= */
.ps-empty {
  display: grid;
  justify-items: center;
  gap: var(--ps-space-2);
  padding: var(--ps-space-6) var(--ps-space-4);
  border: 1px dashed var(--ps-control-border);
  border-radius: var(--ps-radius-card);
  color: var(--ps-text-muted);
  text-align: center;
}

.ps-empty__icon {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  margin-bottom: var(--ps-space-1);
  border-radius: 50%;
  background-color: var(--ps-soft);
  color: var(--ps-link);
}

.ps-empty__icon .ps-icon {
  width: 1.5rem;
  height: 1.5rem;
}

.ps-empty__title {
  color: var(--ps-text);
  font-size: var(--ps-text-md);
  font-weight: var(--ps-weight-semibold);
  letter-spacing: 0;
}

.ps-empty__text {
  max-width: 28rem;
  font-size: var(--ps-text-sm);
}

.ps-empty > .ps-btn {
  margin-top: var(--ps-space-2);
}

/* ==== Tabs (switch between the views of one app) ========================== */
.ps-tabs {
  display: flex;
  gap: var(--ps-space-1);
  overflow-x: auto;
  box-shadow: inset 0 -1px 0 var(--ps-line);
  scrollbar-width: thin;
}

.ps-tabs__tab {
  display: inline-flex;
  flex: none;
  align-items: center;
  min-height: var(--ps-target);
  padding: 0 var(--ps-space-3);
  border: 0;
  border-bottom: 3px solid transparent;
  border-radius: 0;
  background-color: transparent;
  color: var(--ps-text-muted);
  font-size: var(--ps-text-sm);
  font-weight: var(--ps-weight-semibold);
  text-decoration: none;
  white-space: nowrap;
}

.ps-tabs__tab:focus-visible {
  outline-offset: -3px;
}

@media (hover: hover) {
  .ps-tabs__tab:hover {
    color: var(--ps-text);
  }
}

.ps-tabs__tab[aria-selected="true"],
.ps-tabs__tab[aria-current="page"] {
  border-bottom-color: var(--ps-primary);
  color: var(--ps-text);
}

/* ==== Content: sections, prose, example, sources, disclaimer ============== */
.ps-section {
  display: grid;
  gap: var(--ps-space-4);
  margin-top: var(--ps-space-7);
}

.ps-section__title {
  font-size: var(--ps-text-2xl);
}

.ps-prose {
  max-width: var(--ps-container-prose);
}

.ps-prose > * + * {
  margin-top: var(--ps-space-4);
}

.ps-prose > h3 {
  margin-top: var(--ps-space-5);
  font-size: var(--ps-text-lg);
}

.ps-prose li + li {
  margin-top: var(--ps-space-1);
}

.ps-prose code {
  padding: 0.1em 0.35em;
  border-radius: 4px;
  background-color: var(--ps-wash);
}

.ps-example {
  max-width: var(--ps-container-prose);
  padding: var(--ps-space-4);
  border: 1px solid var(--ps-line);
  border-radius: var(--ps-radius-panel);
  background-color: var(--ps-wash);
  color: var(--ps-text);
}

.ps-example > * + * {
  margin-top: var(--ps-space-3);
}

.ps-example__title {
  font-size: var(--ps-text-md);
  font-weight: var(--ps-weight-semibold);
  letter-spacing: 0;
}

.ps-sources {
  display: grid;
  gap: var(--ps-space-2);
  max-width: var(--ps-container-prose);
  margin: 0;
  padding-left: 1.25rem;
}

.ps-sources__date {
  color: var(--ps-text-muted);
  font-size: var(--ps-text-sm);
}

.ps-disclaimer {
  max-width: var(--ps-container-prose);
  padding-top: var(--ps-space-4);
  border-top: 1px solid var(--ps-line);
  color: var(--ps-text-muted);
  font-size: var(--ps-text-sm);
}

.ps-reviewed {
  color: var(--ps-text-muted);
  font-size: var(--ps-text-sm);
}

.ps-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.125rem 0.5rem;
  border-radius: var(--ps-radius-pill);
  background-color: var(--ps-soft);
  color: var(--ps-link-hover);
  font-size: var(--ps-text-xs);
  font-weight: var(--ps-weight-semibold);
  line-height: 1.5;
  white-space: nowrap;
}

/* ==== Document sheet (invoice, quote) =====================================
   Always light (tokens.css): it stands for paper. print.css prints it
   alone. */
.ps-doc {
  container: ps-doc / inline-size;
  max-width: 52rem;
  padding: clamp(1rem, 3vw, 2.5rem);
  border: 1px solid var(--ps-line);
  border-radius: var(--ps-radius-sm);
  background-color: var(--ps-surface);
  color: var(--ps-text);
  font-size: var(--ps-text-sm);
  line-height: 1.5;
  box-shadow: var(--ps-shadow-md);
}

.ps-doc__head {
  display: grid;
  gap: var(--ps-space-4);
  padding-bottom: var(--ps-space-4);
  border-bottom: 2px solid var(--ps-text);
}

.ps-doc__title {
  font-size: var(--ps-text-2xl);
  font-weight: var(--ps-weight-bold);
  line-height: 1.1;
}

.ps-doc__meta {
  display: grid;
  grid-template-columns: auto auto;
  justify-content: start;
  gap: 0.125rem var(--ps-space-4);
  margin: var(--ps-space-2) 0 0;
}

.ps-doc__meta dt {
  color: var(--ps-text-muted);
}

.ps-doc__meta dd {
  margin: 0;
  font-weight: var(--ps-weight-semibold);
  font-variant-numeric: tabular-nums;
}

.ps-doc__parties {
  display: grid;
  gap: var(--ps-space-4);
  margin-block: var(--ps-space-5);
}

.ps-doc__party {
  font-style: normal;
}

.ps-doc__party-label {
  margin-bottom: var(--ps-space-1);
  color: var(--ps-text-muted);
  font-size: var(--ps-text-xs);
  font-weight: var(--ps-weight-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.ps-doc__name {
  font-size: var(--ps-text-md);
  font-weight: var(--ps-weight-semibold);
}

.ps-doc__lines-wrap {
  overflow-x: auto;
}

.ps-doc__lines {
  width: 100%;
  font-variant-numeric: tabular-nums;
}

.ps-doc__lines th,
.ps-doc__lines td {
  padding: var(--ps-space-2) var(--ps-space-1);
  border-bottom: 1px solid var(--ps-line);
  text-align: start;
  vertical-align: top;
}

.ps-doc__lines th:first-child,
.ps-doc__lines td:first-child {
  padding-left: 0;
}

.ps-doc__lines th:last-child,
.ps-doc__lines td:last-child {
  padding-right: 0;
}

.ps-doc__lines thead th {
  border-bottom: 1px solid var(--ps-text);
  color: var(--ps-text-muted);
  font-size: var(--ps-text-xs);
  font-weight: var(--ps-weight-semibold);
  vertical-align: bottom;
}

.ps-doc__lines .ps-doc__num {
  text-align: end;
  white-space: nowrap;
}

.ps-doc__totals {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--ps-space-1) 0;
  width: min(100%, 22rem);
  margin: var(--ps-space-4) 0 0 auto;
  font-variant-numeric: tabular-nums;
}

.ps-doc__totals dt {
  color: var(--ps-text-muted);
}

.ps-doc__totals dd {
  margin: 0;
  padding-left: var(--ps-space-5);
  text-align: end;
}

.ps-doc__totals .ps-doc__total {
  padding-top: var(--ps-space-2);
  border-top: 2px solid var(--ps-text);
  color: var(--ps-text);
  font-size: var(--ps-text-md);
  font-weight: var(--ps-weight-bold);
}

.ps-doc__mentions {
  margin-top: var(--ps-space-5);
  padding-top: var(--ps-space-3);
  border-top: 1px solid var(--ps-line);
  color: var(--ps-text-muted);
  font-size: var(--ps-text-xs);
  line-height: 1.5;
}

.ps-doc__mentions > * + * {
  margin-top: var(--ps-space-1);
}

.ps-doc__footer {
  margin-top: var(--ps-space-4);
  color: var(--ps-text-muted);
  font-size: var(--ps-text-xs);
  text-align: center;
}

@container ps-doc (min-width: 480px) {
  .ps-doc__lines th,
  .ps-doc__lines td {
    padding-inline: var(--ps-space-2);
  }

  .ps-doc__lines thead th {
    white-space: nowrap;
  }

  .ps-doc__head {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
  }

  .ps-doc__parties {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ==== Utilities =========================================================== */
.ps-hidden {
  display: none !important;
}

.ps-muted {
  color: var(--ps-text-muted);
}

.ps-num {
  font-variant-numeric: tabular-nums;
}

.ps-print-only {
  display: none !important;
}

/* ==== Forced colours (Windows high contrast) ============================== */
@media (forced-colors: active) {
  .ps-icon,
  .ps-field__error::before,
  .ps-notice::before,
  .ps-toast--success::before,
  .ps-toast--error::before,
  .ps-breadcrumb__item + .ps-breadcrumb__item::before,
  .ps-faq__q::after,
  .ps-app-card::after,
  .ps-connect[data-state="connected"]::before {
    forced-color-adjust: none;
    background-color: CanvasText;
  }

  .ps-select {
    padding-right: 0.75rem;
    background-image: none;
    -webkit-appearance: auto;
    appearance: auto;
  }

  .ps-toggle__track {
    forced-color-adjust: none;
    border: 1px solid CanvasText;
    background-color: Canvas;
  }

  .ps-toggle__track::before {
    background-color: CanvasText;
  }

  .ps-toggle__input:checked + .ps-toggle__track {
    border-color: Highlight;
    background-color: Highlight;
  }

  .ps-toggle__input:checked + .ps-toggle__track::before {
    background-color: HighlightText;
  }

  .ps-segmented__input:checked + .ps-segmented__label,
  .ps-locale__link[aria-current="true"],
  .ps-locale__link[aria-current="page"] {
    forced-color-adjust: none;
    background-color: Highlight;
    color: HighlightText;
  }

  .ps-tabs__tab[aria-selected="true"],
  .ps-tabs__tab[aria-current="page"] {
    border-bottom-color: Highlight;
  }
}
