/*
==============================================================================
CONFIDENTIAL - NON-DISCLOSURE NOTICE
------------------------------------------------------------------------------
This file contains proprietary and confidential information belonging to
The University of Sydney. It is provided under the terms of a Non-Disclosure
Agreement (NDA) and/or Licence Agreement. Any unauthorized copying, sharing, 
or distribution of this code or any part thereof is strictly prohibited.

For the full details of your confidentiality obligations, please refer to
the NDA and/or Licence Agreement under which you have received this code.

© 2023-2025 The University of Sydney. All rights reserved.
==============================================================================
*/

/* CSS Custom Properties for Cogniti */
:root {
  /* Colors */
  --cogniti-color-bg-dark: #343a40;
  --cogniti-color-bg-info: #cff4fc;
  --cogniti-color-bg-mid-gray: #757575;
  --cogniti-color-bg-light-gray: #f9f9f9;
  --cogniti-color-bg-neutral-lighter: #f3f2f1;
  --cogniti-color-bg-success: #d1e7dd;
  --cogniti-color-info-text: #444545;
  --cogniti-color-link: #0d6efd;
  --cogniti-color-neutral-secondary: #605e5c;
  /* Accessible muted foreground — Bootstrap's default text-muted (#6c757d)
     fails 4.5:1 on light surfaces (#f8f9fa, #f7f7f7). Use this token on
     muted text instead. ~7:1 contrast on near-white. */
  --cogniti-color-muted-fg: #495057;
  --cogniti-color-primary: #0078d4;
  --cogniti-color-success-text: #0f5132;
  --cogniti-color-success: #107c10;
  --cogniti-color-warning: #d83b01;
  /* Caution, not blocked — see .cogniti-badge-window-status--soon. */
  --cogniti-color-window-soon: #ffc107;

  /* Font Sizes */
  --cogniti-font-size-sm: 0.75rem;
  --cogniti-font-size-md-sm: 0.875rem;
  --cogniti-font-size-base: 1rem;
  --cogniti-font-size-lg: 1.25rem;
  --cogniti-font-size-xl: 2rem;

  /* Spacing/Padding */
  --cogniti-spacing-lg: 20px;
  --cogniti-padding-badge: 0.25rem 0.5rem;
  --cogniti-spacing-base: 1rem;
  --cogniti-scrollbar-padding: 15px;

  /* Border Radius */
  --cogniti-border-radius-sm: 4px;
  --cogniti-border-radius-md: 8px;
  --cogniti-border-radius-circle: 50%;

  /* Box Shadow */
  --cogniti-box-shadow-left: -5px 0 5px -5px rgba(0, 0, 0, 0.3);
  --cogniti-box-shadow-subtle: 0 2px 4px rgba(0, 0, 0, 0.05);
}

/* Bootstrap sizes a bare legend at 1.5rem, so a fieldset heading outgrows the
   labels beside it. The availability-window fieldset is shared markup across
   the agent, sandbox and mini app editors, so normalise it once here rather
   than per edit form -- three copies had already drifted apart. Anything that
   wants a bigger legend says so with a class (.h5, .fs-6), which outranks
   this. */
legend {
  font-size: var(--cogniti-font-size-base);
}

.bg-badge-neutral {
  background-color: var(--cogniti-color-neutral-secondary);
  color: #fff;
}

/* Card-listing workflow_state badge (snippets/lifecycle-status-badge.html). */
.cogniti-badge-lifecycle {
  background-color: var(--cogniti-color-bg-mid-gray);
  color: #fff;
  font-size: 0.7rem;
  margin-top: -3px;
  vertical-align: middle;
}

/* Published is the one affirmative badge — every other state is a caveat, so
   grey would read as one too. Only rendered where a page opts in via
   ENV['LIFECYCLE_BADGE_SHOW_ACTIVE'] (the galleries and the LTI asset picker).
   --bs-success on white clears 4.5:1. */
.cogniti-badge-lifecycle--live {
  background-color: var(--bs-success);
}

/* Published, compacted: a solid green eye that expands to its label on hover.
   Only the live badge ever compacts (see cognitiLifecycleBadge) — shrinking a
   warning to an icon is how it stops being read. Filled rather than outlined:
   at badge size an outline is hard to pick out against the card. The icon/label
   gap lives on the label so it collapses with it — as icon padding it would
   survive as a stray space after the eye. */
.cogniti-badge-lifecycle-label {
  display: inline-block;
  overflow: hidden;
  white-space: nowrap;
  vertical-align: bottom;
  margin-inline-start: 0.25rem;
  transition: max-width 0.2s ease, opacity 0.2s ease, margin-inline-start 0.2s ease;
}
/* Clipped rather than removed, so the label is still announced. */
.cogniti-badge-lifecycle--compact .cogniti-badge-lifecycle-label {
  max-width: 0;
  opacity: 0;
  margin-inline-start: 0;
}
.cogniti-badge-lifecycle--compact:hover .cogniti-badge-lifecycle-label,
.cogniti-badge-lifecycle--compact:focus-within .cogniti-badge-lifecycle-label {
  max-width: 12rem;
  opacity: 1;
  margin-inline-start: 0.25rem;
}
@media (prefers-reduced-motion: reduce) {
  .cogniti-badge-lifecycle-label {
    transition: none;
  }
}

/* Deleted is the one unfilled badge. */
.cogniti-badge-lifecycle--ghost {
  background-color: transparent;
  border: 1px solid var(--cogniti-color-bg-mid-gray);
  color: var(--cogniti-color-bg-mid-gray);
}

/* UC-137 availability-window badge (snippets/window-status-badge.html) — a
   second, independent card badge alongside .cogniti-badge-lifecycle. Warning
   hue distinguishes it as time-bound rather than a lifecycle state. */
.cogniti-badge-window-status {
  background-color: var(--cogniti-color-warning);
  color: #fff;
  font-size: 0.7rem;
  margin-top: -3px;
  vertical-align: middle;
}

/* Closing soon is a heads-up about an asset that still WORKS, so it must not
   wear the same hue as not-yet-open and closed, which are walls. Amber on near
   black rather than white-on-amber: white would not clear 4.5:1 on any yellow
   light enough to read as caution. */
.cogniti-badge-window-status--soon {
  background-color: var(--cogniti-color-window-soon);
  color: #212529;
}

/* Compacted to its icon, expanding to the label on hover or keyboard focus —
   the same treatment as .cogniti-badge-lifecycle--compact, and the same
   clipped-not-removed label so it stays announced to a screen reader. The
   icon/label gap lives on the label so it collapses with it; as icon padding
   it would survive as a stray space after the hourglass.

   Only the closing-soon badge gets this (see cognitiWindowStatusBadge), for
   the reason stated above .cogniti-badge-lifecycle--compact: shrinking a
   warning to an icon is how it stops being read. not_yet_open and closed are
   walls and state their date outright.

   The compact badge carries tabindex="0" so :focus-within can fire at all —
   nothing inside it is focusable, so without that the label is mouse-only,
   and the Tippy tooltip that carries the same sentence is equally out of
   reach. */
.cogniti-badge-window-status-label {
  display: inline-block;
  overflow: hidden;
  white-space: nowrap;
  vertical-align: bottom;
  margin-inline-start: 0.25rem;
  transition: max-width 0.2s ease, opacity 0.2s ease, margin-inline-start 0.2s ease;
}
.cogniti-badge-window-status--compact .cogniti-badge-window-status-label {
  max-width: 0;
  opacity: 0;
  margin-inline-start: 0;
}
.cogniti-badge-window-status--compact:hover .cogniti-badge-window-status-label,
.cogniti-badge-window-status--compact:focus-within .cogniti-badge-window-status-label {
  /* Roomy enough for a full locale-spelled date and time — the label reads
     "Closes Wed, 3 Jun 2026, 4:50 pm" since cognitiFormatLocalDate stopped
     abbreviating to relative words. */
  max-width: 22rem;
  opacity: 1;
  margin-inline-start: 0.25rem;
}
/* Focusable only because it compacts, so the ring is what tells a keyboard
   user the badge is the thing they just reached. */
.cogniti-badge-window-status--compact:focus-visible {
  outline: 2px solid var(--cogniti-color-bg-dark);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .cogniti-badge-window-status-label {
    transition: none;
  }
}

/* Lifecycle workflow-state switcher (agent/sandbox edit pages) — status icon,
   shared across the collapsed button and each dropdown option. Dropdown
   items get the wider Bootstrap item padding as their icon/label gap; the
   button is tighter since it's only clearing its own label. */
.cogniti-workflow-icon {
  margin-right: 0.4rem;
}
.cogniti-workflow-option .cogniti-workflow-icon {
  margin-right: var(--bs-dropdown-item-padding-x);
}
.cogniti-workflow-option {
  display: flex;
  flex-direction: column;
  white-space: normal;
}
.cogniti-workflow-option-row {
  display: flex;
  align-items: center;
}
.cogniti-workflow-option-desc {
  margin-left: calc(2 * var(--bs-dropdown-item-padding-x));
}
.cogniti-workflow-check {
  margin-left: auto;
}
/* The Deleted stand-in for the switcher (snippets/workflow_state_status.html).
   It borrows .btn geometry so the header keeps the same shape in the deleted
   state, but it is a status display, not a control: neutralise the hover and
   active states .btn-outline-secondary brings by pinning them to their
   resting values, and take the button's arrow cursor rather than the I-beam a
   bare span would show over its label.

   Grey, not the switcher's blue: blue is reserved for what can be acted on,
   and lifecycle state is carried by the icon and label rather than by hue —
   the same rule the card badges follow (.cogniti-badge-lifecycle). */
.cogniti-workflow-deleted {
  --bs-btn-hover-color: var(--bs-btn-color);
  --bs-btn-hover-bg: transparent;
  --bs-btn-hover-border-color: var(--bs-btn-border-color);
  --bs-btn-active-color: var(--bs-btn-color);
  --bs-btn-active-bg: transparent;
  --bs-btn-active-border-color: var(--bs-btn-border-color);
  cursor: default;
}
/* Page header row (agent-edit, sandbox-edit): heading on the inline-start
   side, action buttons pinned to the inline-end side. */
.cogniti-page-header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
}
.cogniti-page-header h1 {
  margin: 0;
}
.cogniti-header-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-inline-start: auto;
}
/* The workflow switcher (or its Deleted-state badge stand-in, mutually
   exclusive with it) is always the end-most action, regardless of where
   its macro call sits relative to sibling buttons in the template. */
.cogniti-header-action-end {
  order: 1;
}
/* Wide enough for the per-state descriptions, but never wider than the
   viewport: this menu is dropdown-menu-end aligned, so a fixed 320px would
   push the page sideways on a narrow phone. */
#cognitiWorkflowSwitcher .dropdown-menu {
  width: 320px;
  max-width: calc(100vw - 1.5rem);
}

html,
body {
  height: 100%;
  /* Use --brand-body-font when available (set by snippets/branding-styles.html).
     Falls back to Jost on pages that don't render the branding snippet
     (e.g. error pages) so typography stays consistent. */
  font-family: var(--brand-body-font, 'Jost', sans-serif);
}

/* mdtoast.css hardcodes Roboto; the extra `body` qualifier outweighs it so
   toasts follow the app (and user-selected) font like everything else. */
body .mdtoast {
  font-family: var(--brand-body-font, 'Jost', sans-serif);
}

.content {
  margin-left: 60px;
}

/* Sidebar
   Background uses --brand-sidebar (defined in snippets/branding-styles.html
   from the SIDEBAR_COLOR branding setting, which is independent of
   PRIMARY_COLOR) so instance-level branding flows into the navigation chrome.
   Falls back to --cogniti-color-bg-dark on pages that don't render the
   branding snippet (e.g. error pages) and for instances that have not
   customised SIDEBAR_COLOR. */
.sidebar {
  width: 60px;
  background-color: var(--brand-sidebar, var(--cogniti-color-bg-dark));
  /* Derived from the sidebar colour, not assumed white — an org admin may pick a
     light one. Falls back to white on pages without the branding snippet, whose
     sidebar is the default dark grey. */
  color: var(--brand-sidebar-contrast, var(--bs-white));
  height: 100%;
  position: fixed;
  top: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  z-index: 10;
}

.sidebar .visually-hidden-focusable {
  background-color: var(--bs-blue);
  border: none;
  color: var(--bs-white);
  display: inline-block;
  font-size: var(--cogniti-font-size-lg);
  padding: 1rem;
  position: absolute;
  text-align: center;
  text-decoration: none;
  width: 250px;
}

.sidebar-icon {
  /*margin-bottom: 10px;*/
  font-size: 1.2rem;
  width: 60px;
}
.sidebar .nav-link {
  color: var(--brand-sidebar-contrast, var(--bs-white));
  text-align: center;
  padding: 1.0rem 1rem 1.0rem 1rem;
}
.sidebar .nav-link:hover {
  /* Translucent overlay so the hover state works against any sidebar
     background colour (default dark grey or a configured brand primary). */
  background-color: rgba(0, 0, 0, 0.18);
}
.bottom-icon {
  margin-top: auto;
  text-align: center;
}
.bottom-icon .user-image {
  max-width: 20px;
}

.cogniti-home-logo {
  width: 28px;
}
/* Sidebar home/brand row.
   The home slot historically rendered the logo at 60px to fill the sidebar
   for Cogniti's purpose-built bordered circle. Custom-uploaded brand logos
   often have wider or non-square aspect ratios and look oversized at that
   size, so we constrain them to roughly the visual envelope of the other
   sidebar icons. ``object-fit: contain`` preserves the aspect ratio for
   wide marks (e.g. wordmarks) and ``max-width: 100%`` keeps them inside
   the sidebar's 60px slot.
   All padding is forced to 0 (overriding the 1rem inherited from
   ``.sidebar .nav-link``) so the image's ``max-width: 100%`` resolves
   against the full 60px slot width. With the inherited padding, the
   inner content area was only 28px wide and would silently clamp any
   square logo to 28x28 regardless of HOME_LOGO_MAX_HEIGHT. The bottom
   padding stays at 0 because the next row already provides its own top
   padding, giving a balanced gap. */
.cogniti-nav-link-home-custom-logo {
  padding: 0 !important;
  text-align: center !important;
}
.cogniti-nav-link-home-custom-logo .cogniti-home-custom-logo {
  display: inline-block;
  max-width: 100%;
  /* Driven by the HOME_LOGO_MAX_HEIGHT branding field (rendered into
     --brand-home-logo-max-height by snippets/branding-styles.html). The
     literal fallback covers pages that don't include the branding snippet
     (e.g. error pages). */
  max-height: var(--brand-home-logo-max-height, 32px);
  width: auto;
  height: auto;
  object-fit: contain;
}

.spinner-grow-lg {
  width: 3rem;
  height: 3rem;
}

.dropdown-menu.show {
  z-index: 2000;
}

.select2-container {
  z-index:1000;
}
.select2-container--open {
  z-index:15000;
}

/* Chevron visibility */
button.chevron {
    color: var(--bs-body-color);
}

button.chevron .bi-chevron-down {
    transition: transform 0.3s ease;
    transform: rotate(-90deg);
    display: inline-block;
}

button.chevron[aria-expanded="true"] .bi-chevron-down {
    transform: rotate(0deg);
}

/* Eye icon visibility */
.cogniti-toggle-visibility .bi-eye-slash, .cogniti-toggle-visibility .bi-eye {
    display: none;
}
.cogniti-toggle-visibility[aria-expanded="false"] .bi-eye-slash {
    display: inline;
}
.cogniti-toggle-visibility[aria-expanded="true"] .bi-eye {
    display: inline;
}

.cursor-default {
  cursor: default;
}

.cursor-pointer {
  cursor: pointer;
}

.cursor-disabled {
  cursor: not-allowed !important;
}

/* Remap Bootstrap's default font sizes */
h1 {
  font-size: 2rem;
}

h2 {
  font-size: 1.75rem;
}

h3 {
  font-size: 1.5rem;
}

h2.modal-title {
  font-size: var(--cogniti-font-size-lg);
}

/* Allow column header text to wrap instead of truncating with ellipsis */
.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title {
    white-space: normal !important;
}

/* Title at top, filter at bottom — aligns filters across columns with different title heights */
.tabulator .tabulator-header .tabulator-col .tabulator-col-content {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    height: 100%;
}

/* Common Tabulator styles for tables and content */
div.tabulator-table .tabulator-actions-cell a.btn,
div.tabulator-table .tabulator-actions-cell button {
  display: inline-block;
  min-height: 24px;
  min-width: 24px;
  padding-top: 0;
  text-align: center;
}

div.tabulator-table .tabulator-actions-cell > :first-child {
    margin-left: -0.75rem;
}

div.tabulator-table .tabulator-actions-cell > :last-child {
    margin-right: 0;
}

div.tabulator-table .tabulator-row.tabulator-group span.badge.bg-primary{
  color: #fff;
}

div.cogniti-global-announcement p:last-of-type {
  margin-bottom: 0;
}

/* ============================================================================
   Common Layout Classes
   ============================================================================ */

/* Base layout for all page content areas */
.page-content {
    width: 100%;
    padding: var(--cogniti-spacing-lg);
}

/* Responsive transition for collapsible sidebars */
.page-content-transition {
    transition: width 0.3s ease-in-out;
}

/* ============================================================================
   Responsive Sidebar Styles
   ============================================================================ */

/* Sidebar toggle button - hidden by default, shown on mobile */
.sidebar-toggle {
  position: fixed;
  top: 0.5rem;
  left: 0.5rem;
  z-index: 11;
  background: var(--cogniti-color-bg-dark);
  border: none;
  color: white;
  padding: 0.35rem 0.5rem;
  border-radius: var(--cogniti-border-radius-sm);
  display: none;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  cursor: pointer;
  transition: background-color 0.2s ease;
}

.sidebar-toggle:hover {
  background: #555;
}

.sidebar-toggle:focus {
  outline: 2px solid var(--cogniti-color-primary);
  outline-offset: 2px;
}

/* Sidebar overlay - covers content when sidebar is open on mobile */
.sidebar-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 9;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0.3s ease;
}

body.sidebar-open .sidebar-overlay {
  opacity: 1;
  visibility: visible;
}

@media (max-width: 767.98px) {
  body.sidebar-open {
    overflow: hidden;
  }

  .sidebar {
    transform: translateX(-100%);
    transition: transform 0.3s ease;
    box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.25);
  }

  body.sidebar-open .sidebar {
    transform: translateX(0);
  }

  body.sidebar-open .sidebar-toggle {
    display: none;
  }

  .sidebar-toggle {
    display: inline-flex;
  }

  .content {
    margin-left: 0;
    padding: 1.5rem 1rem 1rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .sidebar,
  .sidebar-overlay,
  .sidebar-toggle {
    transition: none !important;
  }
}

/* Simulation Mode Styles */

/* Simulation icon link - accent color background with white icon */
.sidebar .simulation-icon-link {
  background-color: var(--brand-accent) !important;
  color: #fff !important;
  padding: 0.5rem 1rem !important; /* Reduced padding for slimmer look */
}

.sidebar .simulation-icon-link i {
  font-size: 1.4rem !important; /* Larger icon */
}

.sidebar .simulation-icon-link:hover {
  background-color: var(--brand-accent) !important;
  filter: brightness(1.1);
  color: #fff !important;
}

/* Notification Bell Styles */
.notification-bell-container {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.notification-bell-container .nav-link {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  position: relative;
}

.notification-bell-container .notification-badge {
  position: absolute;
  top: 4px;
  left: 70%;
  transform: translateX(-50%);
  background-color: #ffffff;
  color: #dc3545;
  font-size: 0.7rem;
  font-weight: 600;
  padding: 0.15rem 0.5rem;
  min-width: 1.5rem;
  height: 1.25rem;
  line-height: 0.95rem;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  z-index: 10;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}

.notification-bell-container .notification-badge:empty,
.notification-bell-container .notification-badge[data-count="0"] {
  display: none;
}

.notification-bell-container .bi-bell {
  margin-top: 0.3rem;
}

.notification-bell-container .bi-exclamation-triangle-fill {
  margin-top: 0.3rem;
  color: white;
  background-color: var(--brand-accent);
  border-radius: 4px;
  padding: 0.25rem;
  font-size: 1rem;
}

/* =============================================================================
   Locale Selection Modal
   ============================================================================= */

#localeSelectionModal .locale-select-btn {
  text-align: left;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

#localeSelectionModal .locale-select-btn.active {
  pointer-events: none;
}

#localeSelectionModal .locale-select-btn:disabled {
  opacity: 0.6;
}

/* Language selector in user dropdown */
#userLocaleSelector {
  display: flex;
  align-items: center;
}

#currentLocaleName {
  font-weight: 500;
}

/* Section separator inside a sidebar tablist (e.g. agent-edit, organisation-edit,
   sandbox-edit, interactives-edit). Rendered as a presentation-only <li> so AT
   sees a clean tablist of tabs only; sighted users get a visual grouping. */
.cogniti-edit-nav-section {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--bs-secondary-color, #000000);
    margin: 1rem 0 0.25rem;
    list-style: none;
}

ul[role="tablist"] > .cogniti-edit-nav-section:first-child {
    margin-top: 0;
}

/* Controls locked by cognitiApplyReadOnlyToForm.

   Only the DISABLED ones get not-allowed. A readonly text input keeps its
   text cursor on purpose: the point of admitting a read-only viewer is that
   they can read and copy the value, and not-allowed would tell them the
   opposite of what the control actually permits. */
.cogniti-locked-control:disabled,
.cogniti-locked-control[aria-disabled="true"] {
    cursor: not-allowed;
}

/* Bootstrap sets pointer-events:none on a disabled .btn, which suppresses the
   cursor with it. Restoring pointer events does not restore the button: a
   disabled form control fires no click event either way. */
button.cogniti-locked-control:disabled {
    pointer-events: auto;
}

/* The rule above reaches every disabled control, but two of them are not what
   the pointer is actually over, and each vendor stylesheet sets cursor:default
   on the part that is.

   A checkbox or radio is pointed at by its label. Same specificity as
   Bootstrap's rule, and base.css loads after it. */
.cogniti-locked-control:disabled ~ .form-check-label,
.cogniti-locked-control[aria-disabled="true"] ~ .form-check-label {
    cursor: not-allowed;
}

/* select2 hides the real <select> — which is the element carrying the class —
   and renders its own widget as the next sibling. Page-level stylesheets load
   select2 AFTER base.css, so this has to win on specificity, not order. */
.cogniti-locked-control ~ .select2-container--disabled .select2-selection {
    cursor: not-allowed;
}
