/* ══════════════════════════════════════════════════════════════════════════
   canon-chrome.css — the shared app bar and overlays, on canon v5.

   WHY THIS FILE HAD TO EXIST BEFORE ANY PAGE COULD SHIP. The canon replaces
   books.css rather than layering over it (see canon.src.css), and books.css is
   where the app bar lives. Port a page body without this and the page is right
   while the nav above it renders as a row of unstyled links — which is how the
   first port of payments.html came out. The rail is not per-page work; it is the
   prerequisite every Books page shares, so it is one file loaded by all of them.

   A PORT OF THE MARKUP WE HAVE, NOT THE MARKUP THE MOCKUP HAS. The mockup builds
   its rail from utilities on its own elements; the live bar is .books-bar with
   .books-tab / .books-search / .books-theme, assembled at runtime by
   js/books/books-bar.js. Rewriting that DOM would put a JS rewrite in front of
   every page port, so instead the live markup is styled to the mockup's
   measurements: 54px tall, on --surface, one hairline under it, 34px controls,
   6px radii, and the mockup's own hover ground.

   THE THESIS IS rail-canon.css's, because one rail should not argue with
   another: ONE PLACE TO PRESS, ONE PLACE TO TYPE.
     RECESSED — the search, on --sunken. A well is where you PUT something.
     GHOST    — everything else: transparent until hover or open.
     ACCENT   — spent exactly twice at rest: the active tab's underline (where
                you are) and the brand mark (which app you are in). Hot red is
                reserved for a count that is actually unread.
   ══════════════════════════════════════════════════════════════════════════ */

@layer components {

  /* ── The bar ──────────────────────────────────────────────────────────── */
  :root.canon-v5 .topbar.books-bar {
    position: sticky; top: 0; z-index: 30;
    height: 54px; display: flex; align-items: center; gap: 8px;
    padding: 0 12px; margin: 0;
    background: var(--c-surface);
    border-bottom: 1px solid var(--c-border);
    box-shadow: none;
  }
  @media (min-width: 768px) {
    :root.canon-v5 .topbar.books-bar { gap: 16px; padding: 0 20px; }
  }

  /* Back to the hub. A ghost square on the 34px grid the rest of the rail uses. */
  :root.canon-v5 .books-back {
    width: 34px; height: 34px; flex: none;
    display: grid; place-items: center;
    border-radius: 6px; border: 0; background: transparent;
    color: var(--c-muted); text-decoration: none; cursor: pointer;
    transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
  }
  :root.canon-v5 .books-back:hover { color: var(--c-text); background: var(--c-card-2); }
  :root.canon-v5 .books-back i { font-size: 17px; }

  /* The lockup. The app mark is one of the two accents the rail spends. */
  :root.canon-v5 .books-brand {
    display: flex; align-items: center; gap: 8px; flex: none;
    font-size: 14px; font-weight: 600; letter-spacing: -.02em; color: var(--c-text);
  }
  :root.canon-v5 .books-brand img {
    width: 26px; height: 26px; border-radius: 6px; display: block;
  }
  :root.canon-v5 .books-brand b { font-weight: 600; }
  @media (max-width: 640px) { :root.canon-v5 .books-brand span { display: none; } }

  /* ── Sections ─────────────────────────────────────────────────────────── */
  :root.canon-v5 .books-tabs {
    display: flex; align-items: center; gap: 4px; min-width: 0;
    overflow-x: auto; scrollbar-width: none;
  }
  :root.canon-v5 .books-tabs::-webkit-scrollbar { display: none; }

  :root.canon-v5 .books-tab {
    position: relative;
    display: inline-flex; align-items: center; gap: 6px;
    height: 34px; padding: 0 10px; flex: none;
    border-radius: 6px; border: 0; background: transparent;
    font-size: 14px; font-weight: 400; color: var(--c-text-2);
    text-decoration: none; white-space: nowrap; cursor: pointer;
    transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
  }
  :root.canon-v5 .books-tab:hover { color: var(--c-text); background: var(--c-card-2); }

  /* Where you are. The underline is drawn INSIDE the 54px bar rather than on
     its bottom edge, so it cannot be confused with the bar's own hairline. */
  :root.canon-v5 .books-tab.is-active,
  :root.canon-v5 .books-tab[aria-current="page"] {
    color: var(--c-text); font-weight: 500; background: var(--c-card-2);
  }
  :root.canon-v5 .books-tab.is-active::after,
  :root.canon-v5 .books-tab[aria-current="page"]::after {
    content: ""; position: absolute; left: 10px; right: 10px; bottom: -1px;
    height: 2px; border-radius: 2px 2px 0 0; background: var(--c-accent);
  }

  /* ── The one place to type ────────────────────────────────────────────── */
  :root.canon-v5 .books-search {
    position: relative; flex: 1 1 auto; min-width: 0;
    display: flex; justify-content: center; margin: 0 auto;
  }
  :root.canon-v5 .books-search input {
    width: 100%; max-width: 400px; height: 34px;
    padding: 0 64px 0 12px; box-sizing: border-box;
    border-radius: 6px; border: 1px solid var(--c-border);
    background: var(--c-sunken); color: var(--c-text);
    font-family: inherit; font-size: 12px;
    transition: border-color var(--dur) var(--ease);
  }
  :root.canon-v5 .books-search input::placeholder { color: var(--c-cap); }
  :root.canon-v5 .books-search input:focus {
    outline: 2px solid var(--c-accent); outline-offset: 2px; border-color: var(--c-accent);
  }
  /* The shortcut badge. --c-cap, not --c-muted: at 10px the muted ink is 4.10:1
     on the sunken ground it sits over, which is under AA. */
  :root.canon-v5 .books-kbd {
    position: absolute; top: 50%; transform: translateY(-50%);
    right: calc(50% - 200px + 8px);
    font-family: inherit; font-size: 10px; font-weight: 600; letter-spacing: .06em;
    padding: 2px 6px; border-radius: 3px;
    border: 1px solid var(--c-border); background: transparent; color: var(--c-cap);
    pointer-events: none;
  }
  @media (max-width: 820px) { :root.canon-v5 .books-kbd { display: none; } }

  :root.canon-v5 .books-search-results {
    position: absolute; top: calc(100% + 6px); left: 50%; transform: translateX(-50%);
    width: min(100%, 400px); z-index: 40;
    background: var(--c-card); border: 1px solid var(--c-border); border-radius: 10px;
    box-shadow: var(--float); overflow: hidden; padding: 4px;
  }
  :root.canon-v5 .bsr-empty { padding: 14px; font-size: 12px; color: var(--c-muted); text-align: center; }
  :root.canon-v5 .bsr-label {
    font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
    color: var(--c-muted); padding: 8px 10px 4px;
  }
  :root.canon-v5 .bsr-row {
    display: flex; align-items: center; gap: 9px; padding: 8px 10px;
    border-radius: 7px; text-decoration: none; color: var(--c-text); font-size: 13px;
  }
  :root.canon-v5 .bsr-row:hover { background: var(--c-card-2); }
  :root.canon-v5 .bsr-row i { color: var(--c-muted); font-size: 15px; }
  :root.canon-v5 .bsr-row span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
  :root.canon-v5 .bsr-row em { font-style: normal; color: var(--c-muted); font-size: 12px; white-space: nowrap; }

  /* ── Ghost controls ───────────────────────────────────────────────────── */
  :root.canon-v5 .books-theme,
  :root.canon-v5 .books-signout,
  :root.canon-v5 .books-bell {
    width: 34px; height: 34px; flex: none;
    display: grid; place-items: center;
    border-radius: 6px; border: 0; background: transparent;
    color: var(--c-muted); cursor: pointer;
    transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
  }
  :root.canon-v5 .books-theme:hover,
  :root.canon-v5 .books-signout:hover,
  :root.canon-v5 .books-bell:hover { color: var(--c-text); background: var(--c-card-2); }
  :root.canon-v5 .books-theme i,
  :root.canon-v5 .books-signout i,
  :root.canon-v5 .books-bell i { font-size: 17px; }

  /* Install is an offer, not an instruction: a hairline ghost, never the fill. */
  :root.canon-v5 .books-install {
    display: inline-flex; align-items: center; gap: 6px;
    height: 34px; padding: 0 12px; flex: none;
    border-radius: 6px; border: 1px solid var(--c-border);
    background: transparent; color: var(--c-text-2);
    font-family: inherit; font-size: 12px; font-weight: 500; cursor: pointer;
    transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
  }
  :root.canon-v5 .books-install:hover { background: var(--c-card-2); color: var(--c-text); }

  /* The unread count is the one hot thing on a resting rail.
     .books-bell-dot is a SPAN INSIDE the button carrying the number, so it has
     to be positioned against the button or it lands underneath the icon and
     prints as a bare digit below the rail — which is how it first rendered. */
  :root.canon-v5 .books-bell-wrap { position: relative; flex: none; display: flex; }
  :root.canon-v5 .books-bell { position: relative; }
  :root.canon-v5 .books-bell-panel {
    position: absolute; top: calc(100% + 6px); right: 0; z-index: 40;
    min-width: 280px; max-width: min(92vw, 380px);
    background: var(--c-card); border: 1px solid var(--c-border); border-radius: 10px;
    box-shadow: var(--float); overflow: hidden; padding: 4px;
  }
  :root.canon-v5 .books-bell .books-bell-dot,
  :root.canon-v5 .books-bell .nd-badge,
  :root.canon-v5 .books-bell .bell-count {
    position: absolute; top: 3px; right: 3px;
    min-width: 15px; height: 15px; padding: 0 4px; box-sizing: border-box;
    display: grid; place-items: center;
    border-radius: 999px; background: var(--c-danger); color: var(--c-cta-fg);
    font-family: 'Inter', system-ui, sans-serif; font-variant-numeric: tabular-nums;
    font-size: 10px; font-weight: 600; line-height: 1;
  }

  /* Credits. A count, so it reads as ink on a hairline rather than as a state. */
  :root.canon-v5 .books-credits {
    display: inline-flex; align-items: center; gap: 6px;
    height: 34px; padding: 0 12px; flex: none;
    border-radius: 6px; border: 1px solid var(--c-border);
    background: transparent; color: var(--c-text-2);
    font-size: 12px; text-decoration: none; white-space: nowrap;
  }
  :root.canon-v5 .books-credits b {
    font-family: 'Inter', system-ui, sans-serif; font-variant-numeric: tabular-nums; font-weight: 600;
  }
  @media (max-width: 1024px) { :root.canon-v5 .books-credits { display: none; } }

  /* ── Shared skeleton bar (every Books page reaches this; customers/overview
     also carry their own copy from before this existed — harmless, higher
     specificity there wins, same values). A plain pulse: the motion kit's
     airflow seam+sheen came off 10 Nov 2026. ─────────────────────────────────────────────── */
  :root.canon-v5 .sk { display: block; border-radius: 4px; background: var(--c-card-2); animation: cx-canon-pulse 1.4s var(--ease) infinite; }
  @keyframes cx-canon-pulse { 50% { opacity: .45; } }
  @media (prefers-reduced-motion: reduce) {
    :root.canon-v5 .sk, :root.canon-v5.mk-on .sk { animation: none; }
  }

  /* ── The inline button spinner (Save/Send/Sync labels). Every OTHER page in
     the app defines its own .spin/.ti-spin + @keyframes spin (login.css,
     dashboard.css, support.css, …) — Books never got one, so any
     class="ti-loader spin" icon on a Books page (e.g. the Xero-sync spinner,
     expenses-page.js) has had nothing to animate it. Unconditional: this
     restores the plain rotation every other page already has, flag or no
     flag. mk-on adds the one branded touch on top. ─────────────────────── */
  :root.canon-v5 .spin, :root.canon-v5 .ti-spin, :root.canon-v5 [class*="ti-loader"] {
    display: inline-block; animation: cx-canon-spin .8s linear infinite;
  }
  @keyframes cx-canon-spin { to { transform: rotate(360deg); } }
  :root.canon-v5.mk-on .spin, :root.canon-v5.mk-on .ti-spin, :root.canon-v5.mk-on [class*="ti-loader"] {
    color: var(--c-accent);
  }

  /* ── Overlays that also lived in books.css ────────────────────────────── */
  :root.canon-v5 #flash {
    position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%);
    z-index: 100; padding: 10px 16px; border-radius: 10px;
    background: var(--c-card); border: 1px solid var(--c-border);
    box-shadow: var(--float); color: var(--c-text); font-size: 13px;
  }
  :root.canon-v5 #flash:empty { display: none; }

  /* #busy carries no `hidden` attribute and no class of its own — books.css hid
     it with `#busy { display:none }` and showed it by setting display inline. So
     the canon has to hide it the same way, or every page opens with "Working…"
     printed at the bottom. It did, on the first port. */
  :root.canon-v5 #busy {
    display: none; position: fixed; inset: 0; z-index: 200;
    align-items: center; justify-content: center;
    background: color-mix(in srgb, var(--c-bg) 55%, transparent);
    -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
    animation: ndc-busy-in .18s var(--ease) .12s both;
  }
  /* The label rides a card with a spinner. Both arrive after a beat, so a save
     that finishes at once never flashes a card; the overlay takes clicks at once. */
  :root.canon-v5 #busy > div {
    display: inline-flex; align-items: center; gap: 12px; min-width: 180px;
    padding: 14px 20px 14px 16px; border: 1px solid var(--c-border); border-radius: 12px;
    background: var(--c-card); box-shadow: var(--float), var(--lift-edge);
    color: var(--c-text); font-size: 14px; font-weight: 500; letter-spacing: -.005em;
    animation: ndc-busy-card .22s var(--ease) .12s both;
  }
  :root.canon-v5 #busy > div::before {
    content: ""; flex: none; width: 20px; height: 20px; box-sizing: border-box; border-radius: 50%;
    border: 2px solid var(--c-border-2); border-top-color: var(--c-accent);
    animation: ndc-spin .7s linear infinite;
  }
  @keyframes ndc-busy-in { from { opacity: 0; } }
  @keyframes ndc-busy-card { from { opacity: 0; transform: translateY(4px) scale(.98); } }

}

/* ══════════════════════════════════════════════════════════════════════════
   THE DIALOG — the second shared prerequisite, found the same way as the first.

   The canon REPLACES books.css, and `.bk-overlay` / `.bk-modal` are defined
   nowhere else in the repo. Every Books page keeps its add/edit modals as
   legacy markup OUTSIDE the node the canon shell swaps in, so they survive the
   port — unstyled. bills.html shipped that way and nothing caught it, because
   the page check screenshots the page AT REST and a modal is by definition not
   at rest. Under the canon's scoped preflight the result is not "slightly off":
   `border:0` and a transparent background leave a full-bleed run of browser
   default inputs with no overlay, no panel, and no visible edge.

   So the dialog is styled here, once, for every page — and the page check now
   opens the modal and asserts it (see scripts/canon-page-check.js).

   DERIVED, NOT PORTED. None of the seven mockups contains a dialog; they use
   popovers for menus and nothing else. There is no canon dialog to copy, so
   this is built out of the canon's own primitives rather than invented:
   the .card ground and hairline, the 10px panel radius, --float for the lift,
   34px controls at 6px radius, and the rail's thesis for the form — RECESSED
   for anything you type into (a well is where you PUT something), GHOST for
   everything else, ACCENT spent once, on the button that commits.
   ══════════════════════════════════════════════════════════════════════════ */

@layer components {

  :root.canon-v5 .bk-overlay {
    position: fixed; inset: 0; z-index: 60;
    display: flex; align-items: center; justify-content: center; padding: 16px;
    background: color-mix(in srgb, var(--c-ink-deep) 58%, transparent);
  }
  :root.canon-v5 .bk-modal {
    width: 100%; max-width: 460px; max-height: 90vh; overflow-y: auto;
    padding: 20px;
    background: var(--c-card); border: 1px solid var(--c-border);
    border-radius: 10px; box-shadow: var(--float);
    color: var(--c-text); font-size: 13px;
  }
  :root.canon-v5 .bk-modal h3 {
    display: flex; align-items: center; gap: 8px; margin: 0 0 16px;
    font-family: "Sora", system-ui, sans-serif;
    font-size: 16px; font-weight: 600; letter-spacing: -.012em;
  }
  :root.canon-v5 .bk-modal h3 i { color: var(--c-accent); }

  /* ── The form ─────────────────────────────────────────────────────────── */
  :root.canon-v5 .bk-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
  :root.canon-v5 .bk-span2 { grid-column: 1 / -1; }
  @media (max-width: 520px) { :root.canon-v5 .bk-form-grid { grid-template-columns: 1fr; } }

  /* .lbl is the cap, at the cap's weight and tracking — a field label and a
     section cap are the same part of speech. It is --c-cap and not --c-muted:
     muted is 4.10:1 on the card in the light theme, which is under AA. */
  :root.canon-v5 .bk-modal .lbl {
    display: block; margin: 0 0 5px;
    font-size: 10px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
    color: var(--c-cap);
  }
  :root.canon-v5 .bk-modal .lbl .hint { font-weight: 400; letter-spacing: .04em; text-transform: none; }
  /* A label that wraps a checkbox is a sentence ("Don't send this customer
     automated payment reminders"), not a field name: capitals would shout it. */
  :root.canon-v5 .bk-modal .lbl:has(> input[type="checkbox"]) {
    font-size: 13px; font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--c-text);
  }

  :root.canon-v5 .bk-modal input,
  :root.canon-v5 .bk-modal select,
  :root.canon-v5 .bk-modal textarea {
    display: block; width: 100%; min-width: 0; box-sizing: border-box;
    height: 34px; padding: 0 10px;
    background: var(--c-sunken); border: 1px solid var(--c-border); border-radius: 6px;
    color: var(--c-text); font-family: inherit; font-size: 13px;
    transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
  }
  :root.canon-v5 .bk-modal textarea { height: auto; min-height: 72px; padding: 8px 10px; line-height: 1.5; }
  :root.canon-v5 .bk-modal input::placeholder,
  :root.canon-v5 .bk-modal textarea::placeholder { color: var(--c-cap); }
  :root.canon-v5 .bk-modal input:hover,
  :root.canon-v5 .bk-modal select:hover,
  :root.canon-v5 .bk-modal textarea:hover { border-color: var(--c-border-2); }
  :root.canon-v5 .bk-modal input:focus,
  :root.canon-v5 .bk-modal select:focus,
  :root.canon-v5 .bk-modal textarea:focus {
    background: var(--c-card); border-color: var(--c-accent-edge);
    box-shadow: 0 0 0 3px var(--c-accent-soft); outline: none;
  }
  :root.canon-v5 .bk-modal input[type="checkbox"],
  :root.canon-v5 .bk-modal input[type="radio"] {
    width: auto; height: auto; accent-color: var(--c-accent);
  }

  /* A standing note above a form, and a rule between its sections. */
  :root.canon-v5 .bk-note {
    display: flex; align-items: flex-start; gap: 8px; margin: 0 0 14px;
    padding: 9px 11px; border: 1px solid var(--c-border); border-radius: 6px;
    background: var(--c-sunken); color: var(--c-text-2); font-size: 12px; line-height: 1.5;
  }
  :root.canon-v5 .bk-note i { color: var(--c-accent); flex: none; }
  :root.canon-v5 .bk-sec { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--c-border); }
  :root.canon-v5 .bk-sec-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; }

  /* ── The actions ──────────────────────────────────────────────────────── */
  :root.canon-v5 .bk-modal-actions {
    display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 18px;
  }
  :root.canon-v5 .bk-modal-actions .bk-right { display: flex; gap: 8px; margin-left: auto; }

  /* The legacy button names, wearing .btn / .btn.primary. They appear in markup
     the canon shell does not replace, so they are styled wherever they land —
     not only inside a dialog. */
  :root.canon-v5 .btn-primary,
  :root.canon-v5 .btn-ghost,
  :root.canon-v5 .btn-danger-ghost {
    display: inline-flex; align-items: center; gap: 6px; height: 34px; padding: 0 12px;
    border: 1px solid var(--c-border); border-radius: 6px;
    background: var(--c-card); color: var(--c-text);
    font-family: inherit; font-size: 12px; font-weight: 500; white-space: nowrap; cursor: pointer;
    transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
  }
  :root.canon-v5 .btn-ghost:hover { background: var(--c-card-2); border-color: var(--c-border-2); }
  :root.canon-v5 .btn-primary {
    background: var(--c-cta); border-color: var(--c-cta); color: var(--c-cta-fg); font-weight: 600;
  }
  :root.canon-v5 .btn-primary:hover { background: var(--c-cta-h); border-color: var(--c-cta-h); }
  :root.canon-v5 .btn-primary:disabled { opacity: .55; cursor: default; }
  /* feature_motion_kit: one soft pass of light on hover/focus only — an idle
     loop on every primary button at once (several sit on one editor toolbar)
     read as too much, so this fires once per hover rather than ambiently. */
  :root.canon-v5.mk-on .btn-primary { position: relative; overflow: hidden; }
  :root.canon-v5.mk-on .btn-primary::after {
    content: ""; position: absolute; top: 0; bottom: 0; left: -70%; width: 60%;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .5), transparent);
  }
  :root.canon-v5.mk-on .btn-primary:hover::after,
  :root.canon-v5.mk-on .btn-primary:focus-visible::after {
    animation: ndc-btn-flow .7s ease-in-out 1;
  }
  @keyframes ndc-btn-flow { from { left: -70%; } to { left: 120%; } }
  @media (prefers-reduced-motion: reduce) {
    :root.canon-v5.mk-on .btn-primary:hover::after,
    :root.canon-v5.mk-on .btn-primary:focus-visible::after { animation: none; }
  }
  /* Destructive, and quiet until you go near it: the delete in a dialog sits
     beside Cancel and must not compete with Save for the eye. */
  :root.canon-v5 .btn-danger-ghost { color: var(--c-danger); border-color: transparent; background: transparent; }
  :root.canon-v5 .btn-danger-ghost:hover { background: var(--c-danger-soft); border-color: color-mix(in srgb, var(--c-danger) 32%, transparent); }
  :root.canon-v5 .btn-sm { height: 26px; padding: 0 9px; font-size: 11px; }

  /* The undo affordance inside #flash, and the legacy list-head search. */
  :root.canon-v5 .link {
    background: none; border: 0; padding: 0; font: inherit; font-weight: 600;
    color: var(--c-accent); cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
  }
  :root.canon-v5 .inv-search {
    height: 34px; padding: 0 10px; box-sizing: border-box;
    background: var(--c-sunken); border: 1px solid var(--c-border); border-radius: 6px;
    color: var(--c-text); font-family: inherit; font-size: 12px;
  }
  :root.canon-v5 .inv-search::placeholder { color: var(--c-cap); }
  :root.canon-v5 .inv-search:focus { border-color: var(--c-accent-edge); box-shadow: 0 0 0 3px var(--c-accent-soft); outline: none; }
}

@layer components {
  /* THE LIST-HEAD SEARCH. The bills and suppliers shells both used .fld for it,
     and .fld is the Books DOCUMENT field: invisible at rest by design, so an
     invoice line reads as text until you reach for it. On a search box that
     design is a defect: the empty suppliers page drew its search as a line of
     grey placeholder text with no edge at all, and the only screenshot where it
     looked right was the one the harness had just typed into. A search is a
     well, recessed at rest, like the rail's. A document field is never
     type=search, so this cannot reach one. */
  :root.canon-v5 input.fld[type="search"] {
    height: 34px; margin: 0; padding: 0 10px;
    background: var(--c-sunken); border-color: var(--c-border); border-radius: 6px;
    font-size: 12px;
  }
  :root.canon-v5 input.fld[type="search"]:hover { border-color: var(--c-border-2); }
  :root.canon-v5 input.fld[type="search"]:focus { background: var(--c-card); border-color: var(--c-accent-edge); }
}

@layer components {
  /* THE MONEY SUB-NAVIGATION — Payments · Reconcile · Stripe · Square · Drawings,
     rendered by js/books/money-subnav.js. None of the mockups has it; it is a
     segmented control in the canon's own .seg anatomy, one step larger because
     it navigates between pages rather than filtering one: a sunken well, the
     current page lifted onto the card ground, the accent spent on its icon. */
  :root.canon-v5 .mn-sub {
    display: inline-flex; flex-wrap: wrap; gap: 2px; max-width: 100%;
    margin: 0 0 20px; padding: 2px;
    background: var(--c-sunken); border: 1px solid var(--c-border); border-radius: 6px;
  }
  :root.canon-v5 .mn-sub a {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 5px 11px; border-radius: 4px;
    font-size: 12px; font-weight: 500; white-space: nowrap; text-decoration: none;
    color: var(--c-cap);
    transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
  }
  :root.canon-v5 .mn-sub a:hover { color: var(--c-text-2); }
  :root.canon-v5 .mn-sub a.on { background: var(--c-card); color: var(--c-text); box-shadow: var(--lift); }
  :root.canon-v5 .mn-sub a.on i { color: var(--c-accent); }
  :root.canon-v5 .mn-sub i { font-size: 14px; }
  @media (max-width: 560px) {
    :root.canon-v5 .mn-sub { display: flex; }
    :root.canon-v5 .mn-sub a { flex: 1; justify-content: center; }
  }
}

/* ══════════════════════════════════════════════════════════════════════════
   TWO INJECTED WIDGETS, DRAWN IN THE CANON.

   core/dialog.js (confirmDialog, promptDialog) and core/ui/typeahead.js each
   inject an unlayered <style> the first time they are used. Unlayered, those
   rules beat every canon rule, and the dialog's fall back to the retired
   #2563eb blue, so every question a canon page asked arrived in the old design.
   Under the gate both skip their injection and are drawn here, against the
   same class names, in the .bk-modal's language: the card ground, the 10px
   panel, recessed fields, accent spent once on the button that commits.
   ══════════════════════════════════════════════════════════════════════════ */

@layer components {

  /* ── confirmDialog / promptDialog ─────────────────────────────────────── */
  /* display:none at rest; dialog.js sets display:flex to open it. */
  :root.canon-v5 .nd-dialog-overlay {
    position: fixed; inset: 0; z-index: 100000;
    display: none; align-items: center; justify-content: center; padding: 20px;
    background: color-mix(in srgb, var(--c-ink-deep) 58%, transparent);
  }
  :root.canon-v5 .nd-dialog-box {
    width: 100%; max-width: 460px; box-sizing: border-box; padding: 20px;
    background: var(--c-card); border: 1px solid var(--c-border); border-radius: 10px; box-shadow: var(--float);
    color: var(--c-text); font-family: inherit; font-size: 13px; line-height: 1.55;
  }
  :root.canon-v5 .nd-dialog-box:focus { outline: none; }
  :root.canon-v5 .nd-dialog-box.nd-dlg-wide { max-width: 680px; }
  :root.canon-v5 .nd-dialog-box .nd-dlg-title {
    margin: 0 0 8px; font-family: "Sora", system-ui, sans-serif;
    font-size: 16px; font-weight: 600; letter-spacing: -.012em; color: var(--c-text);
  }
  :root.canon-v5 .nd-dialog-box .nd-dlg-msg { margin: 0 0 16px; white-space: pre-wrap; color: var(--c-text-2); }
  :root.canon-v5 .nd-dialog-box .nd-dlg-label {
    display: block; margin: 0 0 6px;
    font-size: 10px; font-weight: 600; letter-spacing: .09em; text-transform: uppercase; color: var(--c-cap);
  }
  :root.canon-v5 .nd-dialog-box .nd-dlg-input {
    display: block; width: 100%; box-sizing: border-box; height: 34px; padding: 0 10px;
    background: var(--c-sunken); border: 1px solid var(--c-border); border-radius: 6px;
    color: var(--c-text); font-family: inherit; font-size: 13px;
    transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
  }
  :root.canon-v5 .nd-dialog-box .nd-dlg-input:focus {
    background: var(--c-card); border-color: var(--c-accent-edge); box-shadow: 0 0 0 3px var(--c-accent-soft); outline: none;
  }
  :root.canon-v5 .nd-dialog-box .nd-dlg-input.nd-dlg-invalid { border-color: var(--c-danger); }
  :root.canon-v5 .nd-dialog-box .nd-dlg-textarea {
    height: auto; min-height: 180px; max-height: 52vh; padding: 8px 10px; line-height: 1.5; resize: vertical; white-space: pre-wrap;
  }
  :root.canon-v5 .nd-dialog-box .nd-dlg-field + .nd-dlg-field { margin-top: 12px; }
  :root.canon-v5 .nd-dialog-box .nd-dlg-hint { margin: 5px 0 0; font-size: 12px; color: var(--c-text-2); }
  :root.canon-v5 .nd-dialog-box .nd-dlg-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }
  :root.canon-v5 .nd-dialog-box .nd-dlg-btn {
    display: inline-flex; align-items: center; justify-content: center; height: 34px; padding: 0 14px; box-sizing: border-box;
    border: 1px solid var(--c-border); border-radius: 6px; background: var(--c-card); color: var(--c-text);
    font-family: inherit; font-size: 12px; font-weight: 500; white-space: nowrap; cursor: pointer;
    transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
  }
  :root.canon-v5 .nd-dialog-box .nd-dlg-btn:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }
  :root.canon-v5 .nd-dialog-box .nd-dlg-cancel:hover { background: var(--c-card-2); border-color: var(--c-border-2); }
  :root.canon-v5 .nd-dialog-box .nd-dlg-ok { background: var(--c-cta); border-color: var(--c-cta); color: var(--c-accent-fg); font-weight: 600; }
  :root.canon-v5 .nd-dialog-box .nd-dlg-ok:hover { background: var(--c-cta-h); border-color: var(--c-cta-h); }
  /* A destructive answer is the danger wash, not a second accent. */
  :root.canon-v5 .nd-dialog-box .nd-dlg-ok.nd-dlg-danger {
    background: var(--c-danger-soft); border-color: color-mix(in srgb, var(--c-danger) 36%, transparent); color: var(--c-on-wash-danger);
  }
  :root.canon-v5 .nd-dialog-box .nd-dlg-ok.nd-dlg-danger:hover { border-color: var(--c-danger); }

  /* ── The typeahead panel ──────────────────────────────────────────────── */
  :root.canon-v5 .ndta {
    position: fixed; z-index: 99999; box-sizing: border-box; max-height: 296px; overflow-y: auto; padding: 4px;
    background: var(--c-card); color: var(--c-text); border: 1px solid var(--c-border-2); border-radius: 8px; box-shadow: var(--float);
    font-size: 13px;
  }
  :root.canon-v5 .ndta-opt { display: flex; align-items: flex-start; gap: 9px; padding: 7px 9px; border-radius: 6px; line-height: 1.3; cursor: pointer; }
  :root.canon-v5 .ndta-opt[aria-selected="true"] { background: var(--c-accent-soft); color: var(--c-on-wash-accent); }
  :root.canon-v5 .ndta-opt i { flex: none; margin-top: 1px; font-size: 15px; color: var(--c-cap); }
  :root.canon-v5 .ndta-opt[aria-selected="true"] i { color: inherit; }
  :root.canon-v5 .ndta-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
  :root.canon-v5 .ndta-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  :root.canon-v5 .ndta-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; color: var(--c-cap); }
  :root.canon-v5 .ndta-opt[aria-selected="true"] .ndta-sub { color: inherit; }
  :root.canon-v5 .ndta-meta { flex: none; margin-top: 1px; font-size: 12px; color: var(--c-cap); }
  :root.canon-v5 .ndta-hl { background: transparent; color: inherit; font-weight: 600; }
  :root.canon-v5 .ndta-note { padding: 8px 10px; font-size: 12px; color: var(--c-cap); }
}

/* ══════════════════════════════════════════════════════════════════════════
   TOASTS AND THE BUSY SPINNER.

   core/toast.js (showToast) and core/feedback.js (withBusy) bring no CSS of their
   own: books.css drew both, and the canon switches books.css off. So on every
   canon page a toast was a line of bare text at the foot of the document, and a
   busy button changed its label while its spinner drew nothing. Drawn here, as
   the #flash panel above is.
   ══════════════════════════════════════════════════════════════════════════ */

@layer components {
  :root.canon-v5 .toast-container {
    position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%); z-index: 1100;
    display: flex; flex-direction: column; align-items: center; gap: 8px; pointer-events: none;
  }
  :root.canon-v5 .toast {
    display: flex; align-items: center; gap: 9px; max-width: min(480px, calc(100vw - 32px)); padding: 10px 16px;
    border: 1px solid var(--c-border); border-radius: 10px; background: var(--c-card); box-shadow: var(--float);
    color: var(--c-text); font-size: 13px; pointer-events: auto; cursor: pointer;
    opacity: 0; transform: translateY(6px); transition: opacity .25s var(--ease), transform .25s var(--ease);
  }
  :root.canon-v5 .toast.visible { opacity: 1; transform: none; }
  :root.canon-v5 .toast.exiting { opacity: 0; transform: translateY(6px); }
  :root.canon-v5 .toast i { flex: none; font-size: 17px; }
  :root.canon-v5 .toast-success i { color: var(--c-on-wash-ok); }
  :root.canon-v5 .toast-error i { color: var(--c-on-wash-danger); }
  :root.canon-v5 .toast-warning i { color: var(--c-on-wash-warn); }
  :root.canon-v5 .toast-info i { color: var(--c-on-wash-accent); }
  :root.canon-v5 .toast-msg { flex: 1; min-width: 0; }
  :root.canon-v5 .toast-actions { display: flex; gap: 6px; margin-left: 4px; }
  :root.canon-v5 .toast-action {
    padding: 0 2px; border: 0; background: none; white-space: nowrap; cursor: pointer;
    font-family: inherit; font-size: 13px; font-weight: 600; color: var(--c-on-wash-accent);
  }
  :root.canon-v5 .toast-action:hover { text-decoration: underline; }

  :root.canon-v5 .spinner {
    display: inline-block; box-sizing: border-box; width: 13px; height: 13px; vertical-align: -2px;
    border: 2px solid color-mix(in srgb, currentColor 25%, transparent); border-top-color: currentColor; border-radius: 50%;
    animation: ndc-spin .7s linear infinite;
  }
  @keyframes ndc-spin { to { transform: rotate(360deg); } }
}

/* ══════════════════════════════════════════════════════════════════════════
   DIRECT-MESSAGING DRAWER: TOKEN BRIDGE.

   The shared messenger (js/messaging/dm.js + dm-ui.js) styles itself from a
   generic token set (--bg-card / --text-primary / --border / --accent …)
   that the app design systems provide — the same contract hub/css/plenum.css
   bridges for the hub. The canon uses its own names (--c-card / --c-text /
   --c-border …), so without this the drawer and its Books/Dispatch topbar
   launcher fell back to their hardcoded dark literals regardless of the
   page's theme. Because --c-* flips with [data-theme], bridging it here
   makes the drawer follow the canon theme automatically.
   ══════════════════════════════════════════════════════════════════════════ */

@layer components {
  :root.canon-v5 .dm-drawer, :root.canon-v5 .dm-launch {
    --bg-card: var(--c-card); --surface-hover: var(--c-card-2);
    --border: var(--c-border); --text-primary: var(--c-text);
    --text-secondary: var(--c-text-2); --text-muted: var(--c-muted);
    --accent: var(--c-accent); --accent-light: var(--c-accent-soft);
  }
}

/* ── Insight chips ─────────────────────────────────────────────────────────
   ndInsightStrip draws these on Dispatch and Customers too, and stands back
   under canon, so without this they had no styles at all there: an icon
   jammed against its words, and chips running together with no gap. */
@layer components {
  :root.canon-v5 .insight-strip { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
  :root.canon-v5 .insight-chip {
    display: inline-flex; align-items: center; gap: 5px; padding: 1px 8px; border: 1px solid var(--c-border); border-radius: 999px;
    background: var(--c-sunken); font-size: 11px; font-weight: 500; line-height: 1.6; color: var(--c-text-2);
  }
  :root.canon-v5 .insight-chip .ti { font-size: 12px; }
  :root.canon-v5 .insight-chip.is-good {
    border-color: color-mix(in srgb, var(--c-ok) 32%, transparent); background: color-mix(in srgb, var(--c-ok) 10%, transparent); color: var(--c-on-wash-ok);
  }
  :root.canon-v5 .insight-chip.is-warn {
    border-color: color-mix(in srgb, var(--c-warn) 34%, transparent); background: color-mix(in srgb, var(--c-warn) 10%, transparent); color: var(--c-on-wash-warn);
  }
  :root.canon-v5 .insight-chip.is-info { color: var(--c-cap); }
}
