/*
 * xoong.css: design tokens and the default look of the admin set. Plain CSS, no build step.
 *
 *   <link rel="stylesheet" href="/@xoong/ui/src/xoong.css">
 *
 * Everything lives in cascade layers, so your own unlayered CSS always wins without specificity fights.
 * Change the look by overriding the custom properties on :root (or on any element, for a region):
 *
 *   :root { --xo-color-accent: #0a7; --xo-radius: 0; }
 */
@layer xoong.tokens, xoong.base, xoong.components;

@layer xoong.tokens {
  :root {
    color-scheme: light dark;
    --xo-font: system-ui, -apple-system, "Segoe UI", sans-serif;
    --xo-font-mono: ui-monospace, "SF Mono", Menlo, monospace;
    --xo-text: 1rem;
    --xo-text-small: 0.875rem;
    --xo-space-1: 0.25rem;
    --xo-space-2: 0.5rem;
    --xo-space-3: 1rem;
    --xo-space-4: 1.5rem;
    --xo-radius: 0.375rem;
    --xo-form-max-width: 28rem; /* generated forms; `none` for editors that should use the whole width */

    --xo-color-bg: light-dark(#f7f8fa, #14161a);
    --xo-color-surface: light-dark(#fff, #1d2026);
    --xo-color-text: light-dark(#1b1f27, #e8eaee);
    --xo-color-muted: light-dark(#5b6472, #9aa3b2);
    --xo-color-border: light-dark(#d9dde4, #343a46);
    --xo-color-control-border: light-dark(#838c9b, #737d90); /* the edge of a button, field or box that holds input: 3:1 against the page (WCAG 1.4.11) */
    --xo-color-accent: light-dark(#2457d6, #7aa2ff);
    --xo-color-accent-text: light-dark(#fff, #0d1117);
    --xo-color-danger: light-dark(#b42318, #ff8a80);
    --xo-color-accent-soft: color-mix(in srgb, var(--xo-color-accent) 14%, var(--xo-color-surface)); /* a tint of the accent: the current item, a selected row, a chip */
    --xo-color-subtle: color-mix(in srgb, var(--xo-color-text) 5%, var(--xo-color-surface)); /* a quiet surface: table header, tab bar, toolbar */
    --xo-color-success: light-dark(#1a7f37, #56d364);
    --xo-color-warning: light-dark(#9a6700, #e3b341);
    --xo-color-inverse: light-dark(#1b1f27, #e8eaee); /* tooltip, toast */
    --xo-color-inverse-text: light-dark(#fff, #14161a);
    --xo-focus-thin: 2px solid var(--xo-color-accent); /* a ring drawn inside a list item */
    --xo-focus-inverse: 3px solid var(--xo-color-inverse-text); /* on an inverse surface (toast, tooltip): the accent ring can fall under 3:1 there */
    --xo-focus: 3px solid var(--xo-color-accent); /* the accent must be 3:1 against the page (WCAG 1.4.11, 2.4.11) */
    --xo-control-height: 2.5rem; /* every button, field and select; the -sm one is for dense toolbars and table rows */
    --xo-control-height-sm: 2rem;
    --xo-control-height-lg: 3rem;
    --xo-control-padding: 0.9rem;
    --xo-control-gap: 0.5rem; /* between an icon and a label, between controls in a toolbar */
    --xo-touch: 2.75rem; /* the smallest comfortable target: set --xo-control-height to it on a touch layout */
    --xo-field-gap: 0.4rem; /* label, control, hint */
    --xo-icon: 1.25rem;
    --xo-shadow-pop: 0 14px 34px -14px color-mix(in srgb, var(--xo-color-text) 55%, transparent), 0 2px 6px color-mix(in srgb, var(--xo-color-text) 10%, transparent); /* menus, popovers */
  }
}

@layer xoong.base {
  :where(body) { margin: 0; font: var(--xo-text) / 1.5 var(--xo-font); color: var(--xo-color-text); background: var(--xo-color-bg); }
  :where(h1, h2, h3) { line-height: 1.25; }
  :where(a) { color: var(--xo-color-accent); }
  :where(:focus-visible) { outline: var(--xo-focus); outline-offset: 2px; }
  :where(button) {
    font: inherit; padding: 0 var(--xo-control-padding); box-sizing: border-box; cursor: pointer;
    color: var(--xo-color-text); background: var(--xo-color-surface);
    border: 1px solid var(--xo-color-control-border); border-radius: var(--xo-radius);
  }
  /* a switch sets its own height (44×24). The 40px minimum would turn it into a square, and height does not override min-height. */
  :where(button:not([role="switch"])) { min-height: var(--xo-control-height); }
  :where(button:hover) { border-color: var(--xo-color-accent); }
  :where(button[aria-busy="true"]) { opacity: 0.6; cursor: progress; }
  :where(input, select, textarea) {
    font: inherit; padding: var(--xo-space-1) var(--xo-space-2); color: inherit; background: var(--xo-color-surface);
    border: 1px solid var(--xo-color-control-border); border-radius: var(--xo-radius);
  }
  :where(input:not([type="checkbox"], [type="radio"], [type="color"], [type="range"], [type="file"]), select) { min-height: var(--xo-control-height); box-sizing: border-box; }
  :where([aria-invalid="true"]) { border-color: var(--xo-color-danger); }
  .xo-visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}

@layer xoong.components {
  /*
   * Admin shell: put class="xo-admin" on <body> (or on <xo-router> itself) and give the layout a <header>, a <nav> and a <main xo-outlet>.
   * Both the plain page and the router form work:
   *
   *   <body class="xo-admin">                                  <body>
   *     <header>..</header><nav>..</nav><main>..</main>          <xo-router class="xo-admin">
   *   </body>                                                      <template xo-layout="shell"><header>..</header><nav>..</nav><main xo-outlet></main></template> ...
   *
   * The router's wrapper elements (<xo-router>, .xo-router-root, .xo-layout) do not generate boxes (display: contents), so the layout's
   * header, nav and main are grid items of the shell. Nested layouts (a <main> inside the outlet) are not touched by these rules.
   */
  xo-router, .xo-router-root, .xo-layout { display: contents; }
  .xo-admin, xo-router.xo-admin { display: grid; min-height: 100vh; grid-template: "header header" auto "nav main" 1fr / 14rem 1fr; }
  :is(.xo-admin, .xo-admin > xo-router, .xo-admin > .xo-router-root, .xo-admin > xo-router > .xo-router-root, .xo-admin > .xo-router-root > .xo-layout, .xo-admin > xo-router > .xo-router-root > .xo-layout) > header { grid-area: header; padding: var(--xo-space-2) var(--xo-space-4); background: var(--xo-color-surface); border-bottom: 1px solid var(--xo-color-border); }
  :is(.xo-admin, .xo-admin > xo-router, .xo-admin > .xo-router-root, .xo-admin > xo-router > .xo-router-root, .xo-admin > .xo-router-root > .xo-layout, .xo-admin > xo-router > .xo-router-root > .xo-layout) > nav { grid-area: nav; padding: var(--xo-space-3); background: var(--xo-color-surface); border-right: 1px solid var(--xo-color-border); }
  :is(.xo-admin, .xo-admin > xo-router, .xo-admin > .xo-router-root, .xo-admin > xo-router > .xo-router-root, .xo-admin > .xo-router-root > .xo-layout, .xo-admin > xo-router > .xo-router-root > .xo-layout) > nav :where(a) { display: block; padding: var(--xo-space-1) var(--xo-space-2); border-radius: var(--xo-radius); text-decoration: none; color: inherit; }
  :is(.xo-admin, .xo-admin > xo-router, .xo-admin > .xo-router-root, .xo-admin > xo-router > .xo-router-root, .xo-admin > .xo-router-root > .xo-layout, .xo-admin > xo-router > .xo-router-root > .xo-layout) > nav :where(a[aria-current="page"]) { background: var(--xo-color-bg); font-weight: 600; }
  :is(.xo-admin, .xo-admin > xo-router, .xo-admin > .xo-router-root, .xo-admin > xo-router > .xo-router-root, .xo-admin > .xo-router-root > .xo-layout, .xo-admin > xo-router > .xo-router-root > .xo-layout) > main { grid-area: main; padding: var(--xo-space-4); min-width: 0; }
  @media (max-width: 40rem) {
    .xo-admin, xo-router.xo-admin { grid-template: "header" auto "nav" auto "main" 1fr / 1fr; }
    :is(.xo-admin, .xo-admin > xo-router, .xo-admin > .xo-router-root, .xo-admin > xo-router > .xo-router-root, .xo-admin > .xo-router-root > .xo-layout, .xo-admin > xo-router > .xo-router-root > .xo-layout) > nav { border-right: 0; border-bottom: 1px solid var(--xo-color-border); }
  }

  .xo-table { position: relative; overflow-x: auto; background: var(--xo-color-surface); border: 1px solid var(--xo-color-border); border-radius: var(--xo-radius); }
  .xo-table table { width: 100%; border-collapse: collapse; }
  :is(.xo-table, xo-table):is([sticky~=start], [sticky~=end]) table,
  .xo-table:has(.xo-sticky-start, .xo-sticky-end) table { border-collapse: separate; border-spacing: 0; } /* a collapsed border does not stay on a sticky cell */
  :is(.xo-table :is(th, td).xo-sticky-start, :is(.xo-table, xo-table)[sticky~=start] tr > :first-child) { position: sticky; inset-inline-start: 0; z-index: 1; background: var(--xo-color-surface); border-inline-end: 1px solid var(--xo-color-border); }
  :is(.xo-table :is(th, td).xo-sticky-end, :is(.xo-table, xo-table)[sticky~=end] tr > :last-child) { position: sticky; inset-inline-end: 0; z-index: 1; background: var(--xo-color-surface); border-inline-start: 1px solid var(--xo-color-border); }
  .xo-table :where(th, td) { padding: var(--xo-space-2) var(--xo-space-3); text-align: start; border-bottom: 1px solid var(--xo-color-border); }
  .xo-table :where(th) { font-size: var(--xo-text-small); color: var(--xo-color-muted); font-weight: 600; }
  .xo-table :where(th button) { all: unset; cursor: pointer; font: inherit; }
  .xo-table :where(th button:focus-visible) { outline: var(--xo-focus); }
  .xo-table :where(tbody tr:last-child td) { border-bottom: 0; }
  .xo-table tbody { transition: opacity 0.15s ease; }
  xo-view[data-refreshing] .xo-table tbody { opacity: 0.6; } /* the rows of the last result stay while the next loads: no collapse, no jump */
  .xo-table .xo-actions { text-align: end; white-space: nowrap; } /* a table cell stays a cell (display: flex dropped its border) */
  .xo-table .xo-actions > * + * { margin-inline-start: var(--xo-space-2); }
  .xo-bulk { display: flex; align-items: center; gap: var(--xo-space-2); padding: var(--xo-space-2); background: var(--xo-color-bg); border-bottom: 1px solid var(--xo-color-border); }
  .xo-filters { display: flex; flex-wrap: wrap; gap: var(--xo-space-2); align-items: center; padding: var(--xo-space-2); border-bottom: 1px solid var(--xo-color-border); }
  /* column-picker: a "Columns" dropdown at the right end of the filter row; a checked box shows its column */
  .xo-columns { position: relative; margin-inline-start: auto; }
  .xo-columns > summary { list-style: none; cursor: pointer; padding: var(--xo-space-1) var(--xo-space-2); color: inherit; background: var(--xo-color-surface); border: 1px solid var(--xo-color-control-border); border-radius: var(--xo-radius); }
  .xo-columns > summary::-webkit-details-marker { display: none; }
  .xo-columns > summary::after { content: "▾"; margin-inline-start: var(--xo-space-2); }
  .xo-columns-panel { position: absolute; inset-inline-end: 0; top: calc(100% + var(--xo-space-1)); z-index: 30; display: grid; gap: 2px; min-width: 12rem; max-height: 20rem; overflow: auto; padding: var(--xo-space-1); background: var(--xo-color-surface); border: 1px solid var(--xo-color-border); border-radius: var(--xo-radius); box-shadow: 0 8px 24px rgb(0 0 0 / 0.18); }
  .xo-columns-panel label { display: flex; align-items: center; gap: var(--xo-space-2); padding: var(--xo-space-1) var(--xo-space-2); border-radius: var(--xo-radius); cursor: pointer; }
  .xo-columns-panel label:hover { background: var(--xo-color-subtle); }
  .xo-table [data-col][hidden] { display: none !important; } /* a hidden column stays hidden in the card layout too */
  .xo-toast { z-index: var(--xo-z-toast, 60); position: fixed; inset-block-end: var(--xo-space-4); inset-inline-end: var(--xo-space-4); max-width: 24rem; margin: 0; padding: var(--xo-space-2) var(--xo-space-3); color: var(--xo-color-danger); background: var(--xo-color-surface); border: 1px solid var(--xo-color-danger); border-radius: var(--xo-radius); }
  .xo-toast[hidden] { display: none; }
  .xo-pager { display: flex; gap: var(--xo-space-2); justify-content: flex-end; padding: var(--xo-space-2); }

  .xo-form { display: grid; gap: var(--xo-space-3); max-width: var(--xo-form-max-width); }
  .xo-object, .xo-array, .xo-group { margin: 0; padding: var(--xo-space-3); border: 1px solid var(--xo-color-border); border-radius: var(--xo-radius); display: grid; gap: var(--xo-space-3); }
  .xo-group { border: 0; padding: 0; }
  .xo-row { display: grid; gap: var(--xo-space-2); padding: var(--xo-space-2); border: 1px dashed var(--xo-color-border); border-radius: var(--xo-radius); }
  .xo-row-actions, .xo-array-add { display: flex; gap: var(--xo-space-2); flex-wrap: wrap; }
  .xo-row-title { font-weight: 600; }
  .xo-handle { cursor: grab; user-select: none; padding: 0 var(--xo-space-1); opacity: .6; align-self: center; }
  .xo-row.xo-dragging { opacity: .5; }
  .xo-row.xo-drop { outline: 2px dashed var(--xo-color-accent, currentColor); outline-offset: 2px; }
  .xo-hint { color: var(--xo-color-muted); font-size: var(--xo-text-small); }
  .xo-object, .xo-array { margin: 0; padding: var(--xo-space-3); border: 1px solid var(--xo-color-border); border-radius: var(--xo-radius); display: grid; gap: var(--xo-space-3); }
  .xo-group { margin: 0; padding: 0; border: 0; display: grid; gap: var(--xo-space-3); }
  .xo-row { display: grid; gap: var(--xo-space-2); padding: var(--xo-space-2); border: 1px dashed var(--xo-color-border); border-radius: var(--xo-radius); }
  .xo-row-actions, .xo-array-add { display: flex; gap: var(--xo-space-2); flex-wrap: wrap; }
  .xo-hint { color: var(--xo-color-muted); font-size: var(--xo-text-small); }
  .xo-field { display: grid; gap: var(--xo-space-1); }
  .xo-field:has(input[type="checkbox"]) { display: flex; align-items: center; gap: var(--xo-space-2); }
  .xo-field:has(> :is(input, select, textarea, xo-combobox, xo-tags, xo-richtext)[required]) > :first-child::after { content: " *"; color: var(--xo-color-danger); } /* a field that must be filled in */
  .xo-error { color: var(--xo-color-danger); font-size: var(--xo-text-small); }
  .xo-form-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--xo-space-2); } /* the submit button and the buttons put inside <xo-form> */
  .xo-form > .xo-submit, .xo-form-actions > .xo-submit { justify-self: start; color: var(--xo-color-accent-text); background: var(--xo-color-accent); border-color: transparent; }

  xo-view:not(:defined):not(:has(> template[data-xo-template])) { visibility: hidden; } /* raw {name} templates are not shown while the script loads; a prerendered view (@xoong/ssr keeps its template aside) is the content and stays visible */
  /* Hide the page while a view still holds an unexpanded host, so the content under it does not jump when the host is replaced. Defining the element is not enough: #start can be later (the module arrived after the document was parsed). A prerender has no host tag in the tree (it sits in the saved template), so the page stays visible. This does not depend on blocking="render". */
  body:has(xo-view :is(xo-table, xo-pager, xo-form)):not(:has(xo-view :is(.xo-table, .xo-pager, .xo-form))) { visibility: hidden; }
  xo-table, xo-pager, xo-form { display: none; } /* these tags are replaced inside <xo-view> and are never defined. Until then, and outside a view where they are never expanded, the raw host and its children are not shown and take no box */
  .xo-confirm { max-width: 26rem; padding: var(--xo-space-4); color: inherit; background: var(--xo-color-surface); border: 1px solid var(--xo-color-border); border-radius: var(--xo-radius); }
  .xo-confirm::backdrop { background: rgb(0 0 0 / 0.45); }
  .xo-confirm-actions { display: flex; gap: var(--xo-space-2); justify-content: flex-end; margin-top: var(--xo-space-3); }
  .xo-confirm-ok { color: var(--xo-color-accent-text); background: var(--xo-kind, var(--xo-color-danger)); border-color: transparent; } /* red unless the dialog has a kind */
  .xo-confirm[data-buttons="choices"] .xo-confirm-ok { --xo-kind: var(--xo-color-accent); } /* the kind colours the icon; a "Save" stays the accent */
  .xo-confirm-danger { color: var(--xo-color-accent-text); background: var(--xo-color-danger); border-color: transparent; }
  .xo-confirm-body { display: flex; gap: var(--xo-space-3); align-items: flex-start; }
  .xo-confirm-icon { flex: none; width: 1.5rem; height: 1.5rem; fill: none; stroke: var(--xo-kind, currentColor); stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
  .xo-confirm-content { flex: 1; min-width: 0; display: grid; gap: var(--xo-space-2); }
  .xo-confirm-content > * { margin: 0; }
  .xo-confirm-title { padding: 0; border: 0; font-size: 1.1rem; line-height: 1.3; }
  .xo-confirm-field { display: grid; gap: var(--xo-space-1); }
  .xo-confirm-field input[aria-invalid="true"] { border-color: var(--xo-color-danger); }
  .xo-confirm[data-kind="info"] { --xo-kind: var(--xo-color-accent); }
  .xo-confirm[data-kind="success"] { --xo-kind: var(--xo-color-success); }
  .xo-confirm[data-kind="warning"] { --xo-kind: var(--xo-color-warning); }
  .xo-confirm[data-kind="danger"] { --xo-kind: var(--xo-color-danger); }
  .xo-toast :where(button:focus-visible) { outline: var(--xo-focus-inverse); }
  .xo-toast-action { margin-inline-start: var(--xo-space-2); }
  .xo-toast-status { color: var(--xo-color-text); border-color: var(--xo-color-border); }
  xo-dialog > dialog { padding: var(--xo-space-4); color: inherit; background: var(--xo-color-surface); border: 1px solid var(--xo-color-border); border-radius: var(--xo-radius); }
  xo-dialog > dialog::backdrop { background: rgb(0 0 0 / 0.45); }
  xo-dialog > dialog.xo-modal { width: min(40rem, calc(100vw - 2rem)); max-height: min(90vh, 52rem); padding: 0; overflow: hidden; }
  xo-dialog > dialog.xo-modal[open] { display: flex; flex-direction: column; }
  xo-dialog > dialog.xo-modal--sm { width: min(26rem, calc(100vw - 2rem)); }
  xo-dialog > dialog.xo-modal--wide { width: min(60rem, calc(100vw - 2rem)); }
  xo-dialog > dialog.xo-modal--full { width: min(96rem, calc(100vw - 2rem)); }
  .xo-modal__head { display: flex; align-items: center; justify-content: space-between; gap: var(--xo-space-3); padding: var(--xo-space-2) var(--xo-space-2) var(--xo-space-2) var(--xo-space-3); border-bottom: 1px solid var(--xo-color-border); }
  .xo-modal__head h2 { margin: 0; padding: 0; border: 0; font-size: 1.1rem; }
  .xo-modal__body { --xo-modal-pad: var(--xo-space-3); flex: 1; min-height: 0; padding: var(--xo-modal-pad); overflow: auto; }
  /* a form in a dialog uses the dialog's width (the 28rem cap is for a form on a page), and its buttons stay at the bottom while the fields scroll */
  xo-dialog > dialog { --xo-form-max-width: none; }
  .xo-modal__body .xo-form-actions { position: sticky; bottom: calc(-1 * var(--xo-modal-pad)); z-index: 1; margin: 0 calc(-1 * var(--xo-modal-pad)) calc(-1 * var(--xo-modal-pad)); padding: var(--xo-space-2) var(--xo-modal-pad); background: var(--xo-color-surface); border-top: 1px solid var(--xo-color-border); }
  .xo-modal__foot { display: flex; align-items: center; justify-content: flex-end; gap: var(--xo-space-2); padding: var(--xo-space-2) var(--xo-space-3); border-top: 1px solid var(--xo-color-border); }
}
/* Unlayered, so it beats every layered display ( .xo-pager is flex, .xo-form is grid, and the same for a control host or a rule in mist.css ). A stylesheet loaded later still wins. */
[hidden] { display: none; }
