/* ==========================================================================
   SophIA UI — utility classes for the design tokens in theme.css.
   Replaces the template's inline style="color:rgb(var(--s-...))" attributes
   so Razor files carry no style attributes (Context Lock rule 4).
   Naming follows Tailwind: text-*, bg-*, border-*; "-soft" is a 16% tint.
   ========================================================================== */

/* text */
.text-fg { color: rgb(var(--s-fg)); }
.text-muted { color: rgb(var(--s-muted)); }
.text-brand { color: rgb(var(--s-brand)); }
.text-brand-fg { color: rgb(var(--s-brand-fg)); }
.text-accent { color: rgb(var(--s-accent)); }
.text-ok { color: rgb(var(--s-ok)); }
.text-warn { color: rgb(var(--s-warn)); }
.text-err { color: rgb(var(--s-err)); }

/* backgrounds */
.bg-page { background-color: rgb(var(--s-bg)); }
.bg-surface { background-color: rgb(var(--s-surface)); }
.bg-surface-2 { background-color: rgb(var(--s-surface-2)); }
.bg-brand { background-color: rgb(var(--s-brand)); }
.bg-accent { background-color: rgb(var(--s-accent)); }
.bg-ok { background-color: rgb(var(--s-ok)); }
.bg-warn { background-color: rgb(var(--s-warn)); }
.bg-err { background-color: rgb(var(--s-err)); }

/* soft tints (blurred blobs, icon discs, alert boxes) */
.bg-brand-soft { background-color: rgb(var(--s-brand) / .16); }
.bg-accent-soft { background-color: rgb(var(--s-accent) / .16); }
.bg-ok-soft { background-color: rgb(var(--s-ok) / .14); }
.bg-warn-soft { background-color: rgb(var(--s-warn) / .14); }
.bg-err-soft { background-color: rgb(var(--s-err) / .14); }

/* borders */
.border-line { border-color: rgb(var(--s-line)); }
.border-brand { border-color: rgb(var(--s-brand)); }
.border-err { border-color: rgb(var(--s-err) / .4); }
.border-ok { border-color: rgb(var(--s-ok) / .4); }
.border-warn { border-color: rgb(var(--s-warn) / .4); }

/* ---------------------------------------------------------------------------------------------
   Busy state for long actions (setup wizard, admin forms).
   Hand-written rather than Tailwind utilities: the classes are added by script at run time, and
   the compiled Tailwind of each host only contains what its markup mentions.
   --------------------------------------------------------------------------------------------- */
@keyframes sophia-spin { to { transform: rotate(360deg); } }
@keyframes sophia-sweep { from { transform: translateX(-100%); } to { transform: translateX(400%); } }

.busy-spinner {
  display: inline-block;
  width: 1rem;
  height: 1rem;
  flex: none;
  border-radius: 9999px;
  border: 2px solid rgb(255 255 255 / .45);
  border-top-color: currentColor;
  animation: sophia-spin .7s linear infinite;
  vertical-align: -.2em;
}

.btn.is-busy { opacity: .75; cursor: progress; }
.btn:disabled { opacity: .5; cursor: not-allowed; }

/* The step bar becomes indeterminate while an action runs, so the header shows something is happening.
   The track clips it and the sweep is a transform: animating a margin pushed the bar past the viewport, which
   grew the page and left a horizontal scrollbar sliding back and forth for as long as the action ran. */
div:has(> .progress-bar) { overflow: hidden; }
.progress-bar.is-indeterminate { width: 25% !important; animation: sophia-sweep 1.1s ease-in-out infinite; }

.busy-note {
  display: flex;
  align-items: center;
  gap: .625rem;
  margin-top: 1rem;
  padding: .75rem 1rem;
  border-radius: .75rem;
  border: 1px solid rgb(var(--s-line));
  background: rgb(var(--s-brand) / .08);
  color: rgb(var(--s-fg));
  font-size: 13px;
}

.busy-note .busy-spinner { border-color: rgb(var(--s-brand) / .3); border-top-color: rgb(var(--s-brand)); }

@media (prefers-reduced-motion: reduce) {
  .busy-spinner, .progress-bar.is-indeterminate { animation: none; }
}

/* Show/hide control on password fields (js/common/password.js builds it at run time). */
.reveal-wrap { position: relative; display: block; }
.reveal-input { padding-right: 2.5rem; }
.reveal-toggle {
  position: absolute;
  top: 50%;
  right: .5rem;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  border: 0;
  border-radius: .5rem;
  background: transparent;
  color: rgb(var(--s-muted));
  cursor: pointer;
}
.reveal-toggle:hover { color: rgb(var(--s-fg)); background: rgb(var(--s-surface-2)); }
.reveal-toggle:focus-visible { outline: 2px solid rgb(var(--s-brand)); outline-offset: 1px; }

/* Account menu under the person's name, in the chat shell and the admin shell (Pages/Shared/_UserMenu.cshtml).
   The trigger sits in the sidebar footer, so the menu opens upward; when the sidebar is collapsed to a rail,
   menu.js places it beside the rail instead. Hand-written for the same reason as the busy state: both hosts use
   it and neither host's compiled Tailwind needs to know. */
.user-menu { position: relative; }
.menu.menu-up { top: auto; bottom: calc(100% + .35rem); left: .5rem; right: .5rem; }

/* Collapsed rail (desktop only; on small screens the sidebar is a full-width drawer and shows its labels).
   A nav group's hidden label keeps flex-1 from the expanded layout, so it still claimed the free width: the icon sat
   against the left edge with an empty gap beside it. And a group looked exactly like a link, although clicking it
   opens a side panel with the group's items (rail.js). The label now takes no space, and a group carries a small
   arrow pointing where its panel opens. */
@media (min-width: 1024px) {
  .app.is-collapsed .collapse-hide { flex: 0 0 0; }
  .app.is-collapsed [data-nav-group-toggle] { position: relative; }
  .app.is-collapsed [data-nav-group-toggle]::after {
    content: "";
    position: absolute;
    top: 50%;
    right: .55rem;
    width: 0;
    height: 0;
    border-top: 4px solid transparent;
    border-bottom: 4px solid transparent;
    border-left: 4px solid currentColor;
    opacity: .55;
    transform: translateY(-50%);
    pointer-events: none;
  }
  .app.is-collapsed [data-nav-group-toggle]:hover::after,
  .app.is-collapsed [data-nav-group-toggle]:focus-visible::after { opacity: .9; }

  /* A sidebar button (New chat) is a flex row of icon, gap and label. Collapsed, the label is hidden but the button
     kept its side padding and gap inside a 48px-wide slot, leaving the icon a few pixels: it shrank to a dot and
     nobody could tell what the button was. The icon now keeps the nav icons' size, centred, and the button carries
     the rail's hover tooltip (data-rail-tip, rail.js). */
  .app.is-collapsed .sidebar .btn { gap: 0; padding-left: 0; padding-right: 0; }
  .app.is-collapsed .sidebar .btn svg { width: 18px; height: 18px; flex: none; }

  /* The account menu under the name. Beside the collapsed rail menu.js positions it with top and left; the upward
     anchoring from the expanded layout (bottom) then squeezed it to a thin outline with its items spilling out
     unpainted. And its trigger kept the stretched link box, whose hover background sat misaligned around the round
     avatar. The menu drops the upward anchoring and the trigger is a round avatar button. */
  .app.is-collapsed .menu.menu-up { bottom: auto; right: auto; }
  .app.is-collapsed .user-menu > [data-menu-trigger] {
    width: 40px;
    height: 40px;
    margin: 0 auto;
    padding: 0;
    gap: 0;
    border-radius: 9999px;
    justify-content: center;
  }
}
