/* main — the shell's own rules.
 *
 * Each rule is scoped `:where(.spoke-shell)`, which adds zero specificity, so no rule can change
 * which one wins.
 *
 * The ROOT gets no rule at all. The root `.spoke-shell` wraps `.spoke-app`,
 * `#spoke-toast` and `#spoke-reset-overlay` so Anvil does not add a wrapper of
 * its own; `.spoke-app` keeps its own rule as an inner div.
 *
 * NOT here, and deliberately: `*`, `body`, `.loading-spinner`, its `::before`
 * and `@keyframes spin`. All five are app-global rather than shell-scoped and
 * live in `theme/assets/spoke/spoke_shared.css`; scoping the first two to
 * `.spoke-shell` would NARROW what they reach, which is a behaviour change, and
 * `body` cannot be scoped at all.
 *
 * ORDER AUDIT. `main.css` sorts FIRST among the spoke links, so on a
 * specificity tie a leaf's rule beats the shell's. No class declared here is declared by
 * any other spoke form, no `.px-*` class selector appears, and
 * `px-critical-tokens` declares custom properties plus a dark-band `body`
 * background/colour rule. This file declares no `body` rule, so nothing ties.
 *
 * No designer gate is needed: nothing here hides content until JavaScript runs
 * that the markup does not already hide.
 */

:where(.spoke-shell) .spoke-app { display: flex; flex-direction: column; min-height: 100vh; background: var(--px-bg-deep); }

/* Top bar */
:where(.spoke-shell) .spoke-topbar {
  background: var(--px-accent); color: var(--px-accent-on); display: flex; align-items: center;
  justify-content: space-between; padding: 0 20px; height: 56px; flex-shrink: 0;
  box-shadow: 0 2px 4px rgba(0,0,0,0.15);
}
:where(.spoke-shell) .spoke-topbar-title { font-size: 18px; font-weight: 600; letter-spacing: 0.3px; }
:where(.spoke-shell) .spoke-topbar-group { display: flex; align-items: center; gap: 12px; }
:where(.spoke-shell) .spoke-topbar-user { font-size: 13px; opacity: 0.85; }
/* Active-spoke switcher — hidden unless the user belongs to 2+ spokes */
:where(.spoke-shell) .spoke-switcher {
  display: none; background: rgba(255,255,255,0.12); color: var(--px-accent-on);
  border: 1px solid rgba(255,255,255,0.4); border-radius: 4px;
  padding: 6px 10px; font-size: 13px; font-family: inherit; cursor: pointer;
  max-width: 260px;
}
:where(.spoke-shell) .spoke-switcher.visible { display: inline-block; }
:where(.spoke-shell) .spoke-switcher option { color: var(--px-accent-fg); background: var(--px-bg-input); }
/* Single-spoke label (switcher hidden): show which spoke is active */
:where(.spoke-shell) .spoke-active-name { display: none; font-size: 13px; opacity: 0.85; }
:where(.spoke-shell) .spoke-active-name.visible { display: inline; }
:where(.spoke-shell) .spoke-topbar-btn {
  background: none; border: 1px solid rgba(255,255,255,0.4); color: var(--px-accent-on);
  padding: 6px 14px; border-radius: 4px; cursor: pointer; font-size: 13px;
}
:where(.spoke-shell) .spoke-topbar-btn:hover { background: rgba(255,255,255,0.15); }

/* Nav tabs */
:where(.spoke-shell) .spoke-nav {
  display: flex; background: var(--px-bg-card); border-bottom: 2px solid var(--px-border);
  padding: 0 20px; flex-shrink: 0;
}
:where(.spoke-shell) .spoke-nav-tab {
  padding: 12px 24px; cursor: pointer; font-size: 14px; font-weight: 500;
  color: var(--px-text-secondary); border-bottom: 3px solid transparent; transition: all 0.2s;
  user-select: none; background: none; border: none; border-bottom: 3px solid transparent;
  font-family: inherit;
}
:where(.spoke-shell) .spoke-nav-tab:focus-visible { outline: 2px solid var(--px-focus-ring); outline-offset: -2px; }
:where(.spoke-shell) .spoke-nav-tab:hover { color: var(--px-accent-fg); background: var(--px-bg-elevated); }
:where(.spoke-shell) .spoke-nav-tab.active { color: var(--px-accent-fg); border-bottom-color: var(--px-accent-fg); font-weight: 600; }

/* Content area — applies to both static content and child form slot */
:where(.spoke-shell) .spoke-content, :where(.spoke-shell) #spoke-child-forms { flex: 1; padding: 20px; overflow-y: auto; }

/* Toast — informational only, never captures clicks. The toast uses
   opacity (not display:none) to fade in/out, so its DOM box persists
   and would otherwise block clicks on anything underneath (e.g. the
   Save Pattern button in the Custom Times modal whose footer sits at
   bottom-right, exactly where this toast lives). */
:where(.spoke-shell) .spoke-toast {
  position: fixed; bottom: 20px; right: 20px; padding: 12px 24px;
  border-radius: 6px; font-size: 14px; z-index: 10000;
  box-shadow: 0 4px 12px rgba(0,0,0,0.25); opacity: 0; transition: opacity 0.3s;
  max-width: 400px; pointer-events: none;
}
:where(.spoke-shell) .spoke-toast.visible { opacity: 1; }
:where(.spoke-shell) .spoke-toast.success { background: var(--px-toast-success-bg); color: var(--px-toast-success-text); }
:where(.spoke-shell) .spoke-toast.error { background: var(--px-toast-error-bg); color: var(--px-toast-error-text); }
/* `danger` is the shared toolkit's spelling of the same severity
   (PX_TOAST_TYPES: success/error/danger/warning/info). window.pxGlobalToast
   points at showToast in main.mjs, so a toolkit call using `danger` renders
   through this node and would otherwise land with no background at all. */
:where(.spoke-shell) .spoke-toast.danger { background: var(--px-toast-error-bg); color: var(--px-toast-error-text); }
:where(.spoke-shell) .spoke-toast.warning { background: var(--px-toast-warning-bg); color: var(--px-toast-warning-text); }
:where(.spoke-shell) .spoke-toast.info { background: var(--px-toast-info-bg); color: var(--px-toast-info-text); }
/* Size variant the shared toolkit asks for (PX_TOAST_SIZES.large). */
:where(.spoke-shell) .spoke-toast.spoke-toast-large {
  max-width: 560px; font-size: 15px; padding: 16px 28px;
}

/* Training environment banner — shown only in the "Spoke Training"
   env via setTrainingMode(). High-visibility amber, persists on every
   tab because it lives on the main shell above the child form slot. */
:where(.spoke-shell) .spoke-training-banner {
  display: none; background: var(--px-warning); color: var(--px-ink-on-bright); text-align: center;
  font-size: 13px; font-weight: 700; letter-spacing: 0.5px;
  padding: 7px 16px; flex-shrink: 0;
  box-shadow: inset 0 -1px 0 rgba(0,0,0,0.2);
}
:where(.spoke-shell) .spoke-training-banner.visible { display: block; }

/* Last-reset-failed notice — dismissible inline banner (NOT the
   blocking overlay); shown on fresh loads when the most recent reset
   task terminated unsuccessfully. */
:where(.spoke-shell) .spoke-reset-failure-notice {
  display: none; background: var(--px-danger-bg); color: var(--px-danger-text);
  border-bottom: 1px solid var(--px-danger-border); font-size: 13px; font-weight: 600;
  padding: 7px 40px 7px 16px; text-align: center; position: relative;
  flex-shrink: 0;
}
:where(.spoke-shell) .spoke-reset-failure-notice.visible { display: block; }
:where(.spoke-shell) .spoke-reset-failure-dismiss {
  position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  background: none; border: none; color: var(--px-danger-text); font-size: 16px;
  font-weight: 700; cursor: pointer; line-height: 1; padding: 2px 6px;
}

/* Reset training data button — topbar, Spoke Training env only. */
:where(.spoke-shell) .spoke-reset-btn {
  display: none; background: var(--px-warning); border: 1px solid rgba(255,255,255,0.6);
  color: var(--px-ink-on-bright); padding: 6px 14px; border-radius: 4px; cursor: pointer;
  font-size: 13px; font-weight: 600; font-family: inherit;
}
:where(.spoke-shell) .spoke-reset-btn:hover:not(:disabled) {
  /* Lightened, not darkened: the ink is dark, and a darker amber drops it below 4.5:1. */
  background: color-mix(in srgb, var(--px-warning) 80%, #fff);
}
:where(.spoke-shell) .spoke-reset-btn:disabled {
  background: var(--px-bg-disabled); color: var(--px-text-disabled);
  border-color: var(--px-border-disabled); cursor: not-allowed;
}
:where(.spoke-shell) .spoke-reset-btn.visible { display: inline-flex; }

/* Dark band: the amber fill is lighter, so the button edge goes dark.
   `[data-theme]` is on <html>, an ancestor of the root, so it leads the selector. */
[data-theme="dark"] :where(.spoke-shell) .spoke-reset-btn:not(:disabled) { border-color: rgba(0,0,0,0.35); }
/* Accent text on the dark hover fill is under 4.5:1. */
[data-theme="dark"] :where(.spoke-shell) .spoke-nav-tab:hover { color: var(--px-text-primary); }

/* Reset overlay — client-owned countdown + 1Hz poll state machine. */
:where(.spoke-shell) .spoke-reset-overlay {
  position: fixed; inset: 0; background: rgba(15,20,45,0.92);
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 16px; z-index: 11000;
  opacity: 0; visibility: hidden; transition: opacity 0.25s, visibility 0.25s;
}
:where(.spoke-shell) .spoke-reset-overlay.visible { opacity: 1; visibility: visible; }
:where(.spoke-shell) .spoke-reset-countdown {
  font-size: 64px; font-weight: 600; color: var(--px-backdrop-text); font-variant-numeric: tabular-nums;
}
:where(.spoke-shell) .spoke-reset-status {
  color: var(--px-backdrop-text); font-size: 16px; font-weight: 500; text-align: center;
  max-width: 480px; padding: 0 16px;
}
:where(.spoke-shell) .spoke-reset-actions { display: none; gap: 16px; margin-top: 16px; }
:where(.spoke-shell) .spoke-reset-actions.visible { display: flex; }
:where(.spoke-shell) .spoke-reset-retry, :where(.spoke-shell) .spoke-reset-dismiss {
  padding: 8px 24px; font-size: 14px; font-weight: 500; border-radius: 4px;
  cursor: pointer; border: 1px solid var(--px-backdrop-text); font-family: inherit;
}
:where(.spoke-shell) .spoke-reset-retry { background: var(--px-backdrop-text); color: var(--px-accent); }
:where(.spoke-shell) .spoke-reset-retry:hover { opacity: 0.9; }
:where(.spoke-shell) .spoke-reset-dismiss { background: transparent; color: var(--px-backdrop-text); }
:where(.spoke-shell) .spoke-reset-dismiss:hover { background: rgba(255,255,255,0.1); }

@media (max-width: 768px) {
  :where(.spoke-shell) .spoke-topbar {
    padding: 8px 12px; height: auto; min-height: 56px; flex-wrap: wrap; row-gap: 8px;
  }
  :where(.spoke-shell) .spoke-topbar-group { flex-wrap: wrap; row-gap: 8px; width: 100%; justify-content: flex-end; }
  :where(.spoke-shell) .spoke-topbar-user { display: none; }
  :where(.spoke-shell) .spoke-switcher.visible {
    display: block; flex: 1 0 100%; max-width: 100%;
  }
  :where(.spoke-shell) .spoke-topbar select { font-size: 16px; }
  :where(.spoke-shell) .spoke-topbar-btn, :where(.spoke-shell) .spoke-reset-btn {
    min-height: 44px; min-width: 44px; align-items: center; justify-content: center;
  }
  :where(.spoke-shell) .spoke-topbar-btn { display: inline-flex; }
  :where(.spoke-shell) .spoke-nav-tab { padding: 10px 16px; font-size: 13px; min-height: 44px; }
  :where(.spoke-shell) .spoke-content, :where(.spoke-shell) #spoke-child-forms { padding: 12px; }
  :where(.spoke-shell) .spoke-toast { max-width: calc(100vw - 40px); }
  :where(.spoke-shell) .spoke-toast.spoke-toast-large { max-width: calc(100vw - 40px); }
  :where(.spoke-shell) .spoke-reset-failure-notice { padding-right: 56px; }
  :where(.spoke-shell) .spoke-reset-failure-notice.visible { display: flex; align-items: center;
    justify-content: center; min-height: 44px; }
  :where(.spoke-shell) .spoke-reset-failure-dismiss {
    min-height: 44px; min-width: 44px; display: flex; align-items: center;
    justify-content: center; right: 6px;
  }
}
