/* HOUSE RULES: CARDS, CHIPS, TABLES, NOTICES, TABS AND DIALOGS, the same in every Wildcard app. Source: wildcardsvc/house-rules (web/components.css).
   Apps carry a copy (public/components.css, or public/portal/components.css) made by `house-rules sync`: never edit the copy. It needs
   tokens.css and takes the app's colour through --accent and --focus. The portal's pages are the reference.

   An app may position these (margin, width, flex, grid, align) but not restyle them: no colour, background, border, radius, shadow,
   padding or font on `.pagehead*`, `.admin-mark*`, `.status*`, `.empty*`, `.card*`, `.chip*`, `.tbl*`, `.notice*`, `.note`, `.tabs`, `.tab`, `.dlg*`. The check fails it.

   Chips:    .chip (a short status label), --brand, --ok, --warn, --bad, --ghost, --sm, and --dot for a status dot. Words, not colour alone.
   Tables:   .tbl-wrap > table.tbl (a data table: quiet header, hairlines); th/td.num for numbers (right, tabular), .mid to centre.
   Header:   header.pagehead > h1.pagehead__title (+ --admin for a Wildcard Admin page: the asterisk), p.pagehead__sub, div.pagehead__acts. pageHead() in menu/render.js.
   Status:   p.status[role=status] (+ --ok, --error, --due): what just happened to a control, in words and an icon.
   Empty:    .empty > b (what), p (why/what to do), a.btn; .empty--line for a quiet one-line "None yet."
   Cards:    .card (a section of a page: the sign-in card, a settings section), .card--tile (a compact tile in a grid).
   Notices:  .notice (information), .notice--ok, .notice--warn, .notice--error. Say what happened, in words; colour is not the message.
   Notes:    .note (an aside with an accent edge, inside a page or a card).
   Tabs:     nav.tabs > a.tab[aria-current="page"], or div.tabs[role=tablist] > button.tab[aria-selected="true"].
   Dialogs:  dialog.dlg (440px), .dlg--md (640px), .dlg--lg (900px) > .dlg__head (h2 + a close button), the body, .dlg__acts (buttons). */

/* ---------- page header: the page's one h1, always the name of the menu item the page belongs to; a subheader only if it must */
.pagehead { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 6px 24px; margin: 0 0 28px; }
.pagehead__title { margin: 0; color: var(--text); font: var(--fw-bold) var(--fs-title)/1.1 var(--font-display); letter-spacing: -.02em; text-wrap: balance; }
.pagehead__title--admin { display: flex; align-items: center; gap: .4em; }
.pagehead__sub { grid-column: 1; margin: 0; color: var(--text-2); font-size: var(--fs-body); }
.pagehead__sub:empty { display: none; }
.pagehead__acts { grid-column: 2; grid-row: 1 / span 2; display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 10px; }
@media (max-width: 640px) { .pagehead { grid-template-columns: minmax(0, 1fr); } .pagehead__acts { grid-column: 1; grid-row: auto; justify-content: flex-start; margin-top: 6px; } }
/* a Wildcard Admin page: the logo's asterisk before the title; it takes the app's colour and names itself on hover, focus or tap */
.admin-mark { position: relative; display: inline-grid; place-items: center; width: .6em; height: .6em; flex: none; cursor: default; border-radius: 50%; outline-offset: 6px; }
.admin-mark__icon { width: 100%; height: 100%; background: var(--text); transition: background-color .15s ease; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round'%3E%3Cpath d='M12 3.5v17M4.6 7.75l14.8 8.5M4.6 16.25l14.8-8.5'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round'%3E%3Cpath d='M12 3.5v17M4.6 7.75l14.8 8.5M4.6 16.25l14.8-8.5'/%3E%3C/svg%3E") center / contain no-repeat; }
.admin-mark:hover .admin-mark__icon, .admin-mark:focus .admin-mark__icon { background: var(--accent); }
.admin-mark:hover::after, .admin-mark:focus::after {
  content: attr(data-tip); position: absolute; left: 0; top: calc(100% + 12px); z-index: 20; padding: 6px 14px; border-radius: 999px; background: var(--accent); color: var(--on-accent);
  font: var(--fw-bold) var(--fs-small)/1.5 var(--font-body); letter-spacing: 0; white-space: nowrap; pointer-events: none;
}
@media (prefers-reduced-motion: reduce) { .admin-mark__icon { transition: none; } }

/* ---------- cards */
.card { width: 100%; padding: 32px; border-radius: var(--radius-lg); background: var(--slate); box-shadow: 0 0 0 1px var(--line) inset, 0 24px 48px -28px var(--shade); }
.card--tile { display: grid; gap: 10px; align-content: start; padding: 22px; border-radius: var(--radius); box-shadow: 0 0 0 1px var(--line) inset; }
@media (max-width: 640px) { .card { padding: 22px 18px; } }

/* ---------- chips: a short label that says a state ("Active", "Overdue", "Client") */
.chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 2px 10px; border-radius: 999px; background: var(--ink); box-shadow: 0 0 0 1px var(--line-strong) inset;
  color: var(--text-2); font: var(--fw-bold) var(--fs-small)/1.5 var(--font-body); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.chip--brand { background: var(--plum); box-shadow: none; color: var(--lilac); }
.chip--ok { background: color-mix(in srgb, var(--ok) 14%, transparent); box-shadow: 0 0 0 1px color-mix(in srgb, var(--ok) 45%, transparent) inset; color: var(--ok); }
.chip--warn { background: color-mix(in srgb, var(--warn) 14%, transparent); box-shadow: 0 0 0 1px color-mix(in srgb, var(--warn) 45%, transparent) inset; color: var(--warn); }
.chip--bad { background: color-mix(in srgb, var(--danger-text) 12%, transparent); box-shadow: 0 0 0 1px color-mix(in srgb, var(--danger-text) 45%, transparent) inset; color: var(--danger-text); }
.chip--ghost { background: transparent; box-shadow: 0 0 0 1px var(--fog) inset; color: var(--fog); }
.chip--sm { padding: 1px 8px; font-size: var(--fs-label); }
.chip--dot::before { content: ""; flex: none; width: .5rem; height: .5rem; border-radius: 50%; background: currentColor; }

/* ---------- tables: a data table in a rounded wrapper that scrolls sideways when it must */
.tbl-wrap { overflow-x: auto; border-radius: var(--radius-md); background: var(--slate); box-shadow: 0 0 0 1px var(--line) inset, 0 24px 48px -28px var(--shade); }
.tbl { width: 100%; border-collapse: collapse; }
.tbl th { padding: 12px 11px; border-bottom: 1px solid var(--line); text-align: left; white-space: nowrap; color: var(--text-2); font: var(--fw-bold) var(--fs-small)/1.4 var(--font-body); }
.tbl td { padding: 14px 11px; vertical-align: middle; }
.tbl tbody tr + tr td { border-top: 1px solid var(--line); }
.tbl .num { text-align: right; font-variant-numeric: tabular-nums; }
.tbl .mid { text-align: center; }

/* ---------- status line: the quiet result of an action, beside the control ("Saved", "Could not save"); put it in a live region (role="status") */
.status { margin: 0; min-height: 1.5em; color: var(--text-2); font-size: var(--fs-body); }
.status--ok, .status--error { --status-icon: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M4%2012.5l5%205L20%206.5'%20fill='none'%20stroke='black'%20stroke-width='3'%20stroke-linecap='round'%20stroke-linejoin='round'/%3E%3C/svg%3E"); }
.status--error { --status-icon: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M12%203L2%2021h20L12%203z'%20fill='none'%20stroke='black'%20stroke-width='2.2'%20stroke-linejoin='round'/%3E%3Cpath%20d='M12%2010v5M12%2018v.5'%20stroke='black'%20stroke-width='2.4'%20stroke-linecap='round'/%3E%3C/svg%3E"); }
.status--ok::before, .status--error::before {
  content: ""; display: inline-block; width: 1.05em; height: 1.05em; margin-right: .45em; vertical-align: -.17em;
  background-color: currentColor; -webkit-mask: var(--status-icon) center / contain no-repeat; mask: var(--status-icon) center / contain no-repeat;
}
.status--ok { color: var(--ok); }
.status--error { color: var(--danger-text); font-weight: var(--fw-bold); }
.status--due { color: var(--lilac); }

/* ---------- empty state: nothing here yet, and what to do about it. .empty (a block, the card-suit watermark) or .empty--line (one quiet line) */
.empty { position: relative; display: grid; justify-items: center; gap: 6px; padding: 52px 20px; border-radius: var(--radius); background: var(--slate); box-shadow: 0 0 0 1px var(--line) inset; text-align: center; }
.empty::before { content: ""; width: 84px; height: 92px; margin-bottom: 8px; background: var(--lilac); opacity: .22; transform: rotate(-6deg); -webkit-mask: url(cards.svg) no-repeat center / contain; mask: url(cards.svg) no-repeat center / contain; }
.empty > b { font-size: 1.25rem; font-weight: var(--fw-bold); }
.empty > p { margin: 0 0 12px; max-width: 30rem; color: var(--text-2); }
.empty--line { display: block; padding: 0; background: none; box-shadow: none; text-align: left; color: var(--text-2); }
.empty--line::before { content: none; }

/* ---------- notices */
.notice { padding: 14px 18px; border-radius: var(--radius-md); background: var(--plum); color: var(--text); box-shadow: 0 0 0 1px var(--purple-bright) inset; }
.notice a { color: var(--lilac); }
.notice--ok { background: rgba(60, 150, 100, .18); box-shadow: 0 0 0 1px rgba(90, 200, 140, .5) inset; }
.notice--warn { background: rgba(232, 184, 74, .14); box-shadow: 0 0 0 1px rgba(232, 184, 74, .5) inset; }
.notice--error { background: rgba(190, 60, 60, .2); box-shadow: 0 0 0 1px rgba(230, 100, 100, .55) inset; }
/* each kind has an icon as well as words: colour is never the only message */
.notice--ok::before, .notice--warn::before, .notice--error::before {
  content: ""; display: inline-block; width: 1.05em; height: 1.05em; margin-right: .45em; vertical-align: -.17em;
  background-color: var(--notice-ink); -webkit-mask: var(--notice-icon) center / contain no-repeat; mask: var(--notice-icon) center / contain no-repeat;
}
.notice--ok { --notice-ink: var(--ok); --notice-icon: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M4%2012.5l5%205L20%206.5'%20fill='none'%20stroke='black'%20stroke-width='3'%20stroke-linecap='round'%20stroke-linejoin='round'/%3E%3C/svg%3E"); }
.notice--warn, .notice--error { --notice-icon: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M12%203L2%2021h20L12%203z'%20fill='none'%20stroke='black'%20stroke-width='2.2'%20stroke-linejoin='round'/%3E%3Cpath%20d='M12%2010v5M12%2018v.5'%20stroke='black'%20stroke-width='2.4'%20stroke-linecap='round'/%3E%3C/svg%3E"); }
.notice--warn { --notice-ink: var(--warn); }
.notice--error { --notice-ink: var(--danger-text); }

/* ---------- note: an aside inside a page (a hint, a reminder), quieter than a notice */
.note { padding: .7rem 1rem; border-left: 4px solid var(--accent); border-radius: 0 var(--radius-md) var(--radius-md) 0; background: var(--slate); }
.card .note { background: var(--ink); }

/* ---------- tabs */
.tabs { display: flex; flex-wrap: nowrap; gap: 4px; margin: 0 0 24px; padding: 0; overflow-x: auto; border-bottom: 1px solid var(--line); }
.tab {
  position: relative; flex: none; appearance: none; margin-bottom: -1px; padding: 10px 18px; border: 0; border-bottom: 3px solid transparent; background: none;
  color: var(--text-2); font: inherit; font-weight: var(--fw-bold); text-decoration: none; white-space: nowrap; cursor: pointer;
}
.tab:hover { color: var(--text); }
.tab[aria-selected="true"], .tab[aria-current="page"] { color: var(--text); border-bottom-color: var(--focus); }
.tab:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.tab[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }

/* ---------- dialogs */
.dlg {
  width: min(440px, calc(100vw - 32px)); max-height: calc(100vh - 48px); padding: 24px; border: 0; border-radius: var(--radius); overflow: auto;
  background: var(--slate); color: var(--text); box-shadow: 0 0 0 1px var(--line) inset, 0 28px 70px -16px var(--shade-deep);
}
.dlg::backdrop { background: rgba(8, 5, 16, .7); }
.dlg:not([open]) { display: none; }
.dlg--md { width: min(640px, calc(100vw - 32px)); }
.dlg--lg { width: min(900px, calc(100vw - 32px)); }
.dlg__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 0 0 12px; }
.dlg__head h2 { margin: 0; font-size: var(--fs-body); font-weight: var(--fw-bold); }
.dlg__acts { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px; margin-top: 20px; }
@media (max-width: 640px) { .dlg { padding: 20px 16px; } }
