/* The shell's own rules, beside the design's sheet: what every page needs that no
   screen of the design draws. Prefix py- (UI-355). */

/* What starts hidden until Alpine starts (ALPINE-105). */
[x-cloak] { display: none !important; }

/* The skip link: out of sight until the keyboard reaches it. */
.py-skip {
  position: absolute; inset: var(--py-2) auto auto var(--py-2); z-index: 60;
  padding: var(--py-2) var(--py-4); border-radius: var(--py-r-ctl);
  background: var(--py-ink); color: var(--py-paper); font-weight: 650;
  translate: 0 -200%;
}
.py-skip:focus { translate: 0 0; }

/* The notices region: the page's live region, where answers' notices pile up. */
.py-notices {
  position: fixed; inset: auto 1rem 1rem auto; z-index: 40;
  display: grid; gap: var(--py-2);
  width: min(26rem, calc(100vw - 2rem));
}
@media (max-width: 47.99rem) { .py-notices { inset: auto 0.75rem 4.5rem 0.75rem; width: auto; } }

/* A field the person reaches and types in is kept clear of the bottom edge, where the notices
   pile up, so its hint and what answers it (a step's line beside its button) stay in sight: the
   browser scrolls it up that far as it takes the focus or the caret. */
html { scroll-padding-block-end: 6rem; }

/* The support stamp: a support visit's every screen says so first, as the rubber stamp
   the office presses on what it touched. */
.py-visit {
  position: sticky; top: 0; z-index: 30; height: var(--py-visit-h, 2.75rem);
  display: flex; justify-content: center; align-items: center; max-width: none;
  padding: 0 var(--py-4);
  background: color-mix(in oklch, var(--py-stamp) 10%, var(--py-desk));
  border-bottom: 1px solid color-mix(in oklch, var(--py-stamp) 35%, transparent);
}
.py-visit .py-stamp { rotate: -2deg; }
@media (min-width: 48rem) {
  body:has(> .py-visit) .py-tabs { top: var(--py-visit-h, 2.75rem); height: calc(100dvh - var(--py-visit-h, 2.75rem)); }
}

/* The screens' menu as the ledger's index tabs: one tab per module, with its paper's
   color (the papers of py.css's tab modifiers, set on the module's element and read by
   its tab and its links); the module the page belongs to stands open, its screens on
   the sheet's edge. */
.py-module-core       { --py-tab-paper: var(--py-print); }
.py-module-people     { --py-tab-paper: oklch(0.80 0.08 355); }
.py-module-catalog    { --py-tab-paper: oklch(0.86 0.13 98); }
.py-module-inventory  { --py-tab-paper: oklch(0.78 0.09 160); }
.py-module-sales      { --py-tab-paper: var(--py-folio); }
.py-module-appointments { --py-tab-paper: var(--py-stamp); }
.py-screens {
  display: grid; gap: var(--py-1); align-content: start;
  min-height: 0; overflow-y: auto; scrollbar-width: thin;
  margin-inline-end: -0.4rem; padding-inline-end: 0.4rem; /* room for the tabs that stand out */
}
.py-screens summary { list-style: none; cursor: pointer; }
.py-screens summary::-webkit-details-marker { display: none; }
.py-screens details[open] > summary {
  translate: 0 0; background: var(--py-paper); color: var(--py-ink); font-weight: 700;
  border-end-start-radius: 0;
}
.py-screens-list {
  list-style: none; margin: 0; padding: 0 0 var(--py-2);
  display: grid; background: var(--py-paper);
  border-end-start-radius: var(--py-r-tab);
}
.py-screens-list a {
  display: block; padding: var(--py-1) var(--py-1) var(--py-1) var(--py-2);
  font-size: var(--py-s--1); line-height: 1.25; color: var(--py-ink-soft); text-decoration: none;
  hyphens: auto; overflow-wrap: break-word;
}
.py-screens-list a:hover { color: var(--py-ink); }
.py-screens-list a[aria-current="page"] { color: var(--py-ink); font-weight: 700; box-shadow: inset 3px 0 0 var(--py-tab-paper, var(--py-rule)); }
.py-place-here { font-size: var(--py-s--1); margin: var(--py-1) 0 var(--py-3); }
.py-place h3.py-place-biz { margin-top: var(--py-2); }
@supports not (position-area: block-end) { .py-place { margin: auto; } } /* UI-318: no anchoring, a centered sheet */

/* A branch's home: its screens by module, each group a card with its tab's paper. */
.py-home { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 14rem), 1fr)); gap: var(--py-4); align-items: start; }
.py-home-group {
  display: grid; gap: var(--py-2); padding: var(--py-4);
  background: var(--py-paper); border-radius: var(--py-r-sheet);
  border-top: 4px solid var(--py-tab-paper, var(--py-rule)); outline: 1px solid var(--py-ruling);
}
.py-home-group h2 { font-family: var(--py-f-display); font-stretch: 90%; font-weight: 760; font-size: var(--py-s-1); }
.py-home-group ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.py-home-group a { display: flex; align-items: center; min-height: 2.25rem; text-decoration: none; font-weight: 560; }
.py-home-group a:hover { text-decoration: underline; text-decoration-color: currentColor; }

@media (max-width: 47.99rem) {
  .py-screens { display: flex; flex: 1; overflow: visible; margin: 0; padding: 0; }
  .py-screens details { flex: 1; position: static; }
  .py-screens summary.py-tab { height: 100%; }
  .py-screens-list { position: absolute; inset: auto 0 100% 0; padding: var(--py-2); border-radius: var(--py-r-tab) var(--py-r-tab) 0 0; box-shadow: var(--py-shadow-sheet); }
  .py-tabs .py-who--menu { display: block; flex: none; width: auto; margin: 0; padding: var(--py-2); }
  .py-tabs .py-who--menu strong { display: none; }
}

/* A sheet's blocks, one under another with the grid's air between them: what py.css's
   sheets leave to each screen. */
.py-stack { display: grid; gap: var(--py-4); align-content: start; }
.py-stack > ul { margin: 0; padding-inline-start: var(--py-5); display: grid; gap: var(--py-2); }

/* ---------- The product's components, in the design's language ---------- */
/* What the screens drawn beyond the design wrote alike, once: the design's py.css stays its
   own file, so a port of it is a copy. A screen's sheet sets what its own differs in. */

/* A form's refusals, as Django draws them (`ul.errorlist`, the fields' templates): the
   design's error text (py.css's `.py-error-text`), one under another. */
.errorlist { list-style: none; margin: 0; padding: 0; font-size: var(--py-s--1); font-weight: 600; color: var(--py-danger); }

/* Columns: what the screen holds, and the side sheet that changes it (its width,
   `--py-cols-side`); one column without a side, or below a tablet on its side. */
.py-cols { display: grid; grid-template-columns: minmax(0, 1fr) minmax(18rem, var(--py-cols-side, 24rem)); gap: var(--py-5); align-items: start; }
.py-cols:not(:has(> .py-cols-side)) { grid-template-columns: minmax(0, 1fr); }
.py-cols-main { display: grid; gap: var(--py-5); align-content: start; min-width: 0; }
.py-cols-side { display: grid; gap: var(--py-4); align-content: start; min-width: 0; }
@media (max-width: 60rem) { .py-cols { grid-template-columns: minmax(0, 1fr); } }

/* A part of the page, its heading over what it holds. */
.py-part { display: grid; gap: var(--py-3); align-content: start; min-width: 0; }
:is(.py-part, .py-form, .py-cols-main) > h2 { font-family: var(--py-f-display); font-stretch: 100%; font-weight: 760; font-size: var(--py-s-1); }

/* A form on its sheet: its fields one under another, its button at their start; a form
   alone on the page keeps a form's width (`--narrow`: a sheet alone, centered). */
.py-form { display: grid; gap: var(--py-4); align-content: start; min-width: 0; }
.py-form .py-btn { justify-self: start; }
.py-form fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
.py-form fieldset legend { padding: 0; margin-bottom: var(--py-1); }
.py-form fieldset > div { display: flex; flex-wrap: wrap; gap: 0 var(--py-4); }
.py-form fieldset label { display: inline-flex; align-items: center; gap: var(--py-2); min-height: 2.75rem; }
.py-alone { width: min(100%, 40rem); }
.py-alone--narrow { width: min(100%, 30rem); justify-self: center; }

/* The field grid: short fields side by side, a wide one across. */
.py-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 9.5rem), 1fr)); gap: var(--py-4); align-items: start; }
.py-fields > .py-fields-wide { grid-column: 1 / -1; }

/* A form folded under its heading until it is wanted (a refused one is drawn open): the
   heading's chevron, turned down once open. */
.py-fold > summary { cursor: pointer; list-style: none; display: flex; align-items: center; gap: var(--py-3); padding: 0 var(--py-4); }
.py-fold > summary::-webkit-details-marker { display: none; }
.py-fold > summary::before {
  content: ""; flex: none; inline-size: 0.5rem; block-size: 0.5rem;
  border-inline-end: 2px solid currentColor; border-block-end: 2px solid currentColor;
  rotate: -45deg; transition: rotate 120ms ease;
}
.py-fold[open] > summary::before { rotate: 45deg; }
.py-fold > summary h2 { font: inherit; }

/* Nothing yet: the words in a dashed frame where the list would be. */
.py-empty { padding: var(--py-6) var(--py-5); border: 1.5px dashed var(--py-rule); border-radius: var(--py-r-sheet); text-align: center; max-width: none; }

/* What a record is, as terms and their values. */
.py-facts { margin: 0; display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--py-2) var(--py-4); }
.py-facts dt { color: var(--py-ink-soft); font-size: var(--py-s--1); align-self: baseline; }
.py-facts dd { margin: 0; font-weight: 600; }

/* The cover's foot carries a button on the dark cloth: its ink is the cover's. */
.py-cover-foot .py-btn { color: inherit; border-color: currentColor; }

/* Links that move in place (docs/specs/navigation.md): the frame's chrome, the ledger's
   tabs column and the office's bar, holds still as a group of its own while the screen
   gives way to the next (HTMX-319); reduced motion moves nothing (py.css's rule). */
.py-tabs { view-transition-name: py-tabs; }
.py-bo-bar { view-transition-name: py-bo-bar; }

/* What is being replaced dims while the server answers, nothing moving (HTMX-272): the
   screen under a link pressed (`:active`, as the request leaves on the press) or on its
   way (`py-is-pending`, htmx's mark on the link), and the `main` a history restore
   replaces. 50 ms late, so a quick answer's view transition starts from the screen as
   it was. A link a screen's script answers in a part of it (`hx-get`) dims only that
   part, its screen's sheet says how. A link that is also dragged, or inside what is
   (`py-drags`), dims once its request is on its way: its press may be a drag's start. */
:is(.py-app, .py-bo-app):has(a[data-htmx-powered]:not([hx-get], .py-drags, .py-drags a):active, a.py-is-pending:not([hx-get])) > main,
main.py-is-pending { opacity: 0.55; transition: opacity 0s 0.05s; }

/* Printing: the sheet on white paper, and no column kept for the tabs py.css hides. The
   frame's grid is outside every screen's `main`, so the rule is the shell's, once. */
@media print {
  body { background: white; }
  .py-app { display: block; }
}

/* Capture's tear-off (HTMX-320): the saved order's sheet, named `py-order` by capture.css while a
   save's blank sheet arrives, leaves toward the day's orders, and the blank one settles in its
   place. A view transition's pseudo-elements hang from the root, where no screen's scope reaches,
   so these two rules are the shell's; their keyframes are capture's. */
::view-transition-old(py-order) { animation: py-tear 420ms cubic-bezier(0.5, 0, 0.75, 0) both; transform-origin: 100% 0; }
::view-transition-new(py-order) { animation: py-settle 280ms ease-out 140ms both; }
