/* The hub's palette, in one place.
 *
 * This block was pasted into twenty-seven pages. Nine of them looked
 * different, which is why it sat in the cleanup plan as the messy half - but
 * the differences turned out to be subsets, not disagreements: twenty-six
 * pages agree on every token they share, and the ninth variants were just
 * pages that had never needed --pending or --mono.
 *
 * So there is one palette, and it lives here. Two pages genuinely differ and
 * keep their own overrides after this file:
 *
 *   inventory-print.html - ink on paper, not light on dark
 *   projection.html      - four chart colours nothing else uses
 *
 * A page opts in with one line, before its own <style>:
 *
 *     <link rel="stylesheet" href="/hub.css">
 */
/* A page tall enough to scroll shows a vertical scrollbar; a shorter one
   does not. .wrap below is centered with margin:0 auto, so the scrollbar's
   own width (15-17px) was coming out of one side only, and the centered
   column shifted left or right by half of it depending on which page you
   had just come from - not a fixed direction, which is what made it read
   as random rather than a rule. Reserving the gutter unconditionally, on
   every page whether it scrolls or not, is what makes the centering math
   identical everywhere instead of only when the two neighbouring pages
   happened to agree on height. */
html{scrollbar-gutter:stable}

:root{
  --bg:#0D1113;
  --surface:#171D21;
  --surface-2:#202930;
  --line:#2C363D;
  --ink:#E9EFF2;
  --ink-2:#9AA9B2;
  --ink-3:#6B7A84;
  --accent:#2ED8A7;
  --accent-ink:#08211A;
  --danger:#EC5B5B;
  --pending:#F5B544;
  /* Dev Mode's on-page authoring overlay (marks/selection/marquee/badges)
     uses this instead of --accent -- see the .devmode-el-mark rule below. */
  --devmode-highlight:#FFD23F;
  --ui:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,system-ui,sans-serif;
  --mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
}

/* ---------------------------------------------------------------------
   Page shell: the content column's width, the header's own padding, the
   title, and the subtitle under it (header p - the one-line description
   every page opens with).

   The same drift the palette above was written to stop had happened again,
   one level up: 27 pages, 27 independently-typed copies of each of these
   three rules, and they had wandered - .wrap{max-width} from 560px to
   920px, h1{font-size} from 20px to 28px, header p's color split between
   --ink-3 (the vast majority) and --ink-2 (camera.html and scanner.html,
   which is why their subtitles read lighter than every other page's) and
   its font-size split 14px/14.5px (exercises.html and seven others were
   the smaller group), and header{padding} ranged 20px-38px top, 8px-16px
   bottom, scanner.html the widest spread from the majority. No two
   neighbouring pages agreeing on any of these is what made navigating
   between them visibly resize the window and shift type size and spacing
   with every click.

   One rule for each, here, same as the palette. A page's own <style>
   still wins if it declares one of these properties again after this
   file - that is what keeps dev.html wide enough for source code and
   inventory-print.html its own size for the printed page, both already
   documented as differing on purpose above. Every other page's local
   declaration was the drift itself, not a reason, and has been removed.
   --------------------------------------------------------------------- */
.wrap{max-width:760px}
h1{font-size:24px}
header p{margin:6px 0 0;color:var(--ink-3);font-size:14.5px}
header{padding:22px 0 8px}

/* ---------------------------------------------------------------------
   Messages float with the window instead of sitting in the page.

   Dar kept trying to do something, could not see why it would not work,
   and eventually scrolled to the bottom of a long page to find the answer
   waiting in a grey box. The page had told him; it had just told him
   somewhere he had no reason to look. The autosave failure the same week
   was the identical shape - a status line off the top of the screen.

   So #msg is anchored to the viewport, the way the assistant and
   back-to-top buttons already are. It stays out of the flow entirely when
   there is nothing to say, so no page's layout moves.

   Deliberately #msg and not .msg: assistant.html uses .msg for its chat
   bubbles, and pinning a conversation to the top of the screen would be a
   fine way to break a page while fixing another.
   --------------------------------------------------------------------- */
#msg:empty { display: none; }

#msg:not(:empty) {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 9000;
  display: flex;
  justify-content: center;
  padding: 10px 12px;
  /* the strip itself must never swallow a tap meant for the page */
  pointer-events: none;
}

#msg:not(:empty) > * {
  pointer-events: auto;
  width: 100%;
  max-width: 620px;
  margin: 0;
  box-shadow: 0 6px 22px rgba(0, 0, 0, .45);
  /* opaque: it sits over content now, not beside it */
  background: var(--surface);
  border: 1px solid var(--line);
}

/* Keeps its meaning - only the position changed */
#msg:not(:empty) > .msg.bad  { border-color: var(--danger); }
#msg:not(:empty) > .msg.good { border-color: var(--accent); }

/* Below the autosave alarm, which is the more serious of the two */
.autosave-alarm:not([hidden]) ~ #msg:not(:empty) { top: 96px; }

@media (prefers-reduced-motion: no-preference) {
  #msg:not(:empty) > * { animation: msgIn .18s ease-out; }
  @keyframes msgIn { from { opacity: 0; transform: translateY(-8px); } }
}

/* ---------------------------------------------------------------------
   Pinned banners - hub-pinned.js. A state, not a note: it stays until it
   is used or dismissed. The whole card is the tap target when it has
   somewhere to go, because a phone card with one small live word in it is
   a card you tap twice.
   --------------------------------------------------------------------- */
.pinned-host { position: fixed; top: 0; left: 0; right: 0; z-index: 9500;
  display: flex; flex-direction: column; gap: 8px; padding: 10px 12px;
  pointer-events: none; align-items: center; }

.pinned { pointer-events: auto; width: 100%; max-width: 620px;
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px;
  padding: 14px 16px; border-radius: 12px;
  background: var(--surface); border: 1px solid var(--accent);
  color: var(--ink); text-decoration: none;
  font-family: var(--ui), system-ui, sans-serif;
  box-shadow: 0 8px 26px rgba(0, 0, 0, .5); }

.pinned[hidden] { display: none; }
.pinned-text { display: flex; flex-direction: column; gap: 2px; flex: 1 1 220px; }
.pinned-text strong { font-size: 16px; }
.pinned-text span { font-size: 13.5px; opacity: .78; }
.pinned-actions { display: flex; align-items: center; gap: 10px; }

.pinned-go { background: var(--accent); color: var(--accent-ink);
  border-radius: 8px; padding: 10px 14px; font-size: 15px; font-weight: 600;
  white-space: nowrap; }

.pinned-x { background: none; border: 0; color: var(--ink); opacity: .6;
  font-size: 13.5px; padding: 10px 4px; cursor: pointer;
  font-family: inherit; text-decoration: underline; }
.pinned-x:hover { opacity: 1; }

.pinned-link { cursor: pointer; }
.pinned-link:hover { border-color: var(--accent);
  box-shadow: 0 8px 26px rgba(0, 0, 0, .5), 0 0 0 3px rgba(46, 216, 167, .18); }
.pinned-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Past its useful life - still shown, but no longer dressed as an action */
.pinned.stale { border-color: var(--line); }
.pinned.stale .pinned-go { background: var(--line); color: var(--ink); opacity: .8; }

/* Something is wrong, as opposed to something is ready */
.pinned.bad { border-color: var(--danger); background: #7f1d1d; color: #fff; }
.pinned.bad .pinned-go { background: #fff; color: #7f1d1d; }
.pinned.bad .pinned-x { color: #fff; }

/* A note now sits below any pinned banner rather than on top of it */
.pinned-host:not(:empty) ~ #msg:not(:empty) { top: 86px; }

/* A banner is for the screen. inventory-print.html exists to be put on
   paper, and a pinned card would land across the top of the printout. */
@media print { .pinned-host, #msg { display: none !important; } }

/* ---------------------------------------------------------------------
 * Themed <dialog> modals (DevMode corrective pass, ClaudeCode-Server1,
 * Sonnet 5, 2026-09-21).
 *
 * settings.html and the on-page Dev Mode authoring layer both build
 * `<dialog class="hub-common-modal" data-draggable-modal>` markup and rely
 * on the approved CommonCode ui_modal_engine (see UI_MODAL_ENGINE_README.md)
 * for drag behavior only -- per that component's own README, "the app
 * supplies the shared host markup and styles only." Neither this app's
 * prior settings.html nor the Dar-approved visual reference candidate
 * (ClaudeCode-Server1-Wellness-UserAdmin-Continuation-20260920) actually
 * defined these classes anywhere, so every such dialog rendered as an
 * unstyled native browser <dialog> (white background, default border) --
 * the exact "generic white/light modal over the dark Wellness app"
 * regression this pass is tasked with fixing. Defined once here, every
 * User/Group/Authorization Level modal, the Dev Mode Element Properties /
 * Group Properties / Configure modals, and confirmation dialogs share one
 * themed presentation automatically.
 * ------------------------------------------------------------------- */
.hub-common-modal {
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 0;
  min-width: 320px;
  max-width: min(560px, calc(100vw - 32px));
  max-height: calc(100vh - 64px);
  background: var(--surface);
  color: var(--ink);
  box-shadow: 0 18px 48px rgba(0,0,0,.55);
  font: 14px/1.45 var(--ui);
}
.hub-common-modal::backdrop { background: rgba(3,6,7,.65); }
.hub-common-modal[open] { display: flex; flex-direction: column; }
.hub-common-modal:has(.sec-dim-tree) { width: min(720px, calc(100vw - 32px)); }
.dialog-header {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 14px 16px; border-bottom: 1px solid var(--line);
  background: var(--surface-2); border-radius: 12px 12px 0 0;
  cursor: grab; /* draggable-modal handle */
}
.dialog-header strong { font-size: 15px; color: var(--ink); }
.dialog-header button { background: none; border: 0; color: var(--ink-2);
  font-size: 20px; line-height: 1; cursor: pointer; padding: 2px 6px; border-radius: 6px; }
.dialog-header button:hover { background: var(--line); color: var(--ink); }
.hub-dialog-body { padding: 16px; overflow-y: auto; }
.hub-dialog-body label { display: block; font-size: 12.5px; color: var(--ink-2); margin-bottom: 4px; }
.hub-dialog-body input[type="text"], .hub-dialog-body input[type="search"],
.hub-dialog-body input:not([type]), .hub-dialog-body textarea, .hub-dialog-body select {
  width: 100%; box-sizing: border-box; background: var(--bg); color: var(--ink);
  border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; font: inherit;
}
.hub-dialog-body input:focus, .hub-dialog-body textarea:focus, .hub-dialog-body select:focus {
  outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent);
}
.hub-dialog-body .chk { display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--ink); }
.hub-dialog-actions {
  display: flex; justify-content: flex-end; gap: 8px; padding: 12px 16px;
  border-top: 1px solid var(--line); background: var(--surface-2); border-radius: 0 0 12px 12px;
}
.hub-dialog-actions button, .hub-dialog-body button {
  background: var(--surface-2); color: var(--ink); border: 1px solid var(--line);
  border-radius: 8px; padding: 8px 14px; font: 600 13px var(--ui); cursor: pointer;
}
.hub-dialog-actions button:hover, .hub-dialog-body button:hover { border-color: var(--accent); }
.hub-dialog-actions button.primary, .hub-dialog-body button.primary {
  background: var(--accent); color: var(--accent-ink); border-color: var(--accent);
}
.hub-dialog-actions button.danger { color: var(--danger); border-color: var(--danger); background: transparent; }

/* Security dimension checkbox tree (spec section 12/22/24). */
.sec-dim-tree { display: flex; flex-direction: column; gap: 10px; margin-top: 8px; }
.sec-dim-row { display:grid; grid-template-columns:minmax(125px, .45fr) minmax(0, 1fr); gap:7px 12px; align-items:start; }
.sec-dim-row > label { display: flex; align-items: center; gap: 8px; font-weight: 600; margin:0; }
/* Page-local form CSS commonly styles every input at 100% width. The common
   security dialog must win: a checkbox is a compact tree toggle, never a
   full-row form field. */
.hub-common-modal .sec-dim-tree input[type="checkbox"] {
  width: auto !important; min-width: 0; padding: 0 !important;
  margin: 0; flex: 0 0 auto;
}
/* "Visibility -> inherited from Group" (spec section 27) -- the checkbox
   itself stays unchecked whether truly unconfigured or inherited, so this
   note is the only UI signal distinguishing the two states. */
.devmode-inherited-note { color: var(--ink-2); font-size: 12px; font-weight: 400; }
.sec-dim-children {
  grid-column:2; margin:0; padding-left:12px; border-left:2px solid var(--line);
  display:grid; grid-template-columns:repeat(auto-fit,minmax(130px,1fr)); gap:6px 12px;
}
/* `display: flex` above is author CSS and beats the UA stylesheet's
   `[hidden] { display: none }`, so an explicitly hidden tree branch would
   render open anyway -- this rule restores the collapse (spec section 12:
   a dimension's Authorization Levels stay hidden until its own checkbox is
   checked). */
.sec-dim-children[hidden] { display: none; }
.sec-dim-children .chk[data-locked] { color: var(--ink-2); }
.sec-dim-children .chk { margin:0; min-width:0; }
.sec-dim-children .chk[data-locked] input { accent-color: var(--ink-3); }
.sec-dim-lock-badge {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-3); border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px;
}
.devmode-member { display:flex; gap:7px; align-items:baseline; }
@media (max-width: 520px) {
  .sec-dim-row { grid-template-columns:1fr; }
  .sec-dim-children { grid-column:1; grid-template-columns:1fr; margin-left:18px; }
}
.badge-muted {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-2);
  border: 1px solid var(--line); border-radius: 4px; padding: 1px 6px; margin-left: 6px;
}

/* Sticky Dev Mode toolbar (spec section 20-20.1). */
#devmode-toolbar {
  position: sticky; top: 0; z-index: 2147483000; display: flex; flex-wrap: wrap;
  align-items: center; gap: 8px; padding: 10px 14px; margin: 0 0 14px;
  background: var(--surface); border-bottom: 1px solid var(--line);
  box-shadow: 0 4px 16px rgba(0,0,0,.35); font: 13px var(--ui); color: var(--ink);
}
#devmode-toolbar .devmode-label { font-weight: 700; letter-spacing: .04em; color: var(--accent); margin-right: 4px; }
#devmode-toolbar .devmode-count { color: var(--ink-2); margin-right: 6px; }
#devmode-toolbar button {
  background: var(--surface-2); color: var(--ink); border: 1px solid var(--line);
  border-radius: 7px; padding: 6px 11px; font: 600 12.5px var(--ui); cursor: pointer;
}
#devmode-toolbar button:hover { border-color: var(--accent); }
#devmode-toolbar button.danger { color: var(--danger); border-color: var(--danger); }
#devmode-toolbar button.primary { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
/* The entry control and all element-selection visuals belong exclusively to
   security-authoring.js.  Keeping legacy rules here made the header control
   fixed over the Assistant and painted every target before it was selected. */
#devmode-marquee { position: fixed; z-index: 2147482999; border: 2px solid var(--devmode-highlight);
  background: rgba(255,210,63,.12); pointer-events: none; }
.devmode-id-badge { position: absolute; top: -10px; left: -2px; z-index: 2147482998; background: var(--surface-2);
  color: var(--devmode-highlight); font: 700 10px var(--ui); padding: 1px 5px; border-radius: 4px;
  border: 1px solid var(--devmode-highlight); pointer-events: none; }
/* Shown on every member of a Group, alongside (not instead of) that
   member's own Element ID badge -- Group membership isn't required to be
   spatially contiguous, so this is the robust way to keep the Group ID
   visible "at/near the boundary" regardless of layout. */
.devmode-group-badge { position: absolute; top: -10px; right: -2px; z-index: 2147482998; background: var(--surface-2);
  color: var(--ink-2); font: 700 10px var(--ui); padding: 1px 5px; border-radius: 4px;
  border: 1px dotted var(--ink-2); pointer-events: none; white-space: nowrap; }

/* Add-button toolbar + form-in-a-modal (Health pages: weight, injections,
   medications, documents). Same look as Settings' Add User / Add Group: one
   Add button near the top opens a themed <dialog class="hub-common-modal">
   holding the form. The reset below strips the page-level `form{...}` card
   styling that would otherwise box a form nested inside the dialog. */
.page-add-toolbar { margin-top: 14px; display: flex; gap: 8px; flex-wrap: wrap; }
.page-add-toolbar button {
  appearance: none; background: var(--accent); color: var(--accent-ink);
  border: 1px solid var(--accent); border-radius: 9px; padding: 0 18px;
  font: 600 13px var(--ui); min-height: 36px; cursor: pointer;
}
.page-add-toolbar button:hover { filter: brightness(1.08); }
.hub-common-modal form.hub-dialog-body {
  margin: 0; padding: 16px; background: transparent; border: 0; border-radius: 0;
  display: flex; flex-direction: column; gap: 12px;
}
.hub-common-modal .hub-dialog-body .field + .field { margin-top: 0; }
.hub-common-modal .hub-dialog-body input[type="date"],
.hub-common-modal .hub-dialog-body input[type="number"] {
  width: 100%; box-sizing: border-box; background: var(--bg); color: var(--ink);
  border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; font: inherit;
}
.hub-common-modal .hub-dialog-body input.big {
  font: 600 30px var(--mono); text-align: center; padding: 12px;
}
.hub-common-modal .hub-dialog-body .two { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.hub-common-modal .hub-dialog-body textarea { min-height: 64px; resize: vertical; }
.hub-common-modal .hub-dialog-body .hub-dialog-actions {
  margin: 4px -16px -16px; padding: 12px 16px;
}
.hub-common-modal .hub-dialog-body .modal-msg:empty { display: none; }

/* Native pop-ups opened from inside a modal (the date picker's calendar,
   select lists) follow the element's color-scheme; the hub only has a dark
   theme, so say so and they stop rendering as a white light-mode panel. */
.hub-common-modal { color-scheme: dark; }
