/**
 * Ontology explorer.
 *
 * Every selector is namespaced .skp-onto__* because the block is dropped into
 * pages, and tabs, whose CSS it has never met.
 *
 * This file styles the map and the dialog *shell* only. What goes inside the
 * dialog is the glossary term's own view display, styled by
 * css/glossary-term.css so the record looks the same on its own page as it does
 * in the modal.
 *
 * Sizing is driven by CONTAINER queries, not viewport ones. The explorer is a
 * block: it can be placed in a narrow sidebar on a wide monitor, and it has to
 * lay itself out against the width it was actually given. That also matches the
 * JS, whose zoom curve reads the canvas width rather than the window's.
 */

.skp-onto {
  --skp-onto-ink: #12263f;
  --skp-onto-ink-muted: #6b7c93;
  /* Sampled from the comp (image 3, 2026-08-24). */
  --skp-onto-surface: #ffffff;
  --skp-onto-dot: #e2e8f0;
  --skp-onto-dot-gap: 25px;
  --skp-onto-hairline: #e6ebf0;

  container-type: inline-size;
  container-name: skp-onto;
  font-family: Lexend, system-ui, sans-serif;
  color: var(--skp-onto-ink);
}

.skp-onto *,
.skp-onto *::before,
.skp-onto *::after {
  box-sizing: border-box;
}

/* ---- the map ---------------------------------------------------------- */

/* The chrome scale lives HERE, not on .skp-onto. A container query styles the
   container's descendants, never the container element itself, so custom
   properties set on .skp-onto could never be overridden by @container. */
.skp-onto__frame {
  --skp-onto-inset: 20px;
  --skp-onto-title: 20px;

  position: relative;
  /* A Cytoscape container with no height measures 0 and never paints, so the
     block declares one. dvh rather than vh: on a phone, vh is the tallest the
     viewport ever gets, so a 72vh map is cut off by the browser's own chrome
     until you scroll. The floor keeps it usable in landscape. */
  height: max(340px, min(72vh, 820px));
  height: max(340px, min(72dvh, 820px));
  border: 1px solid var(--skp-onto-hairline);
  border-radius: 16px;
  /* The dotted grid from the comp. It is on the FRAME, not the stage: the
     cytoscape canvas is transparent and gets cleared every repaint, so a
     background painted there would flicker with the layout. Fixed to the
     frame, so it reads as paper the graph sits on rather than something that
     pans with it. */
  background-color: var(--skp-onto-surface);
  background-image: radial-gradient(circle, var(--skp-onto-dot) 1px, transparent 1px);
  background-size: var(--skp-onto-dot-gap) var(--skp-onto-dot-gap);
  overflow: hidden;
}

.skp-onto__stage {
  position: absolute;
  inset: 0;
}

/* ---- chrome ------------------------------------------------------------
   Title and hud are plain text over the map — no plates, no borders, no blur.

   Legibility comes from a halo in the surface colour rather than a backing
   plate or an edge fade. Both of those were tried: a plate is the chrome this
   pass is removing, and a top/bottom gradient veils the terms drawn under it,
   which is worse than the problem it solves. A halo costs nothing and hides
   nothing. */
.skp-onto__title,
.skp-onto__hud {
  text-shadow:
    0 0 4px var(--skp-onto-surface),
    0 0 8px var(--skp-onto-surface),
    0 0 12px var(--skp-onto-surface);
}

.skp-onto__title {
  position: absolute;
  top: var(--skp-onto-inset);
  left: var(--skp-onto-inset);
  z-index: 4;
  margin: 0;
  font-size: var(--skp-onto-title);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.2;
  color: var(--skp-onto-ink);
  pointer-events: none;
}

.skp-onto__hud {
  position: absolute;
  left: var(--skp-onto-inset);
  bottom: var(--skp-onto-inset);
  z-index: 4;
  /* Never let a long term title run under the zoom buttons. */
  max-width: calc(100% - var(--skp-onto-inset) * 2 - 56px);
  font-size: 12px;
  line-height: 1.4;
  color: var(--skp-onto-ink-muted);
  pointer-events: none;
}

/* ---- zoom controls ---------------------------------------------------- */

.skp-onto__zoom {
  position: absolute;
  right: var(--skp-onto-inset);
  bottom: var(--skp-onto-inset);
  z-index: 4;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: #fff;
  border: 1px solid var(--skp-onto-hairline);
  border-radius: 10px;
}

.skp-onto__zoom button {
  /* 40px is the smallest this can be and still be a comfortable target; it
     goes to 44 under (hover: none) below. */
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  font: inherit;
  font-size: 18px;
  line-height: 1;
  color: var(--skp-onto-ink-muted);
}

.skp-onto__zoom button + button {
  border-top: 1px solid var(--skp-onto-hairline);
}

.skp-onto__zoom button:hover {
  background: #f4f7f9;
  color: var(--skp-onto-ink);
}

.skp-onto__zoom button:focus-visible {
  outline: 2px solid #00527b;
  outline-offset: -2px;
}

/* ---- hover tooltip ---------------------------------------------------- */

.skp-onto__tip {
  position: absolute;
  z-index: 6;
  display: none;
  max-width: min(260px, 78cqw);
  padding: 6px 10px;
  transform: translate(-50%, -100%);
  background: var(--skp-onto-ink);
  color: #fff;
  border-radius: 6px;
  font-size: 12px;
  line-height: 1.45;
  pointer-events: none;
}

.skp-onto__error {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: grid;
  place-items: center;
  padding: 24px;
  text-align: center;
  font-size: 14px;
  color: var(--skp-onto-ink-muted);
}

/* ---- term search ---------------------------------------------------------
   A select2 above the map, outside the frame, so it never covers a term.
   Dressed like the List view's search box (css/glossary-list.css): the same
   46px pill, border, type and the theme's magnifier, which here takes the
   place of select2's arrow. Its dropdown is attached inside this box
   (dropdownParent), so these rules can reach it without leaking to other
   select2 widgets on the page; positioned and stacked so the open dropdown
   lies over the map rather than under it. */
.skp-onto__search {
  --skp-onto-search-border: #d5dde5;
  --skp-onto-search-focus: #0081cc;

  position: relative;
  z-index: 7;
  width: min(400px, 100%);
  margin-bottom: 20px;
  font-family: 'Inter', sans-serif;
  font-size: 15px;
}

.skp-onto__search .select2-container--default .select2-selection--single {
  height: 46px;
  background: #fff;
  border: 1px solid var(--skp-onto-search-border);
  border-radius: 999px;
}

.skp-onto__search .select2-container--default.select2-container--focus .select2-selection--single,
.skp-onto__search .select2-container--default.select2-container--open .select2-selection--single {
  border-color: var(--skp-onto-search-focus);
}

/* select2 squares off the side facing an open dropdown; the dropdown here is a
   separate card with a gap, so the pill stays a pill. */
.skp-onto__search .select2-container--default.select2-container--open .select2-selection--single.select2-selection--single {
  border-radius: 999px;
}

.skp-onto__search .select2-container--default .select2-selection--single .select2-selection__rendered {
  padding-left: 22px;
  padding-right: 52px;
  line-height: 44px;
  color: var(--skp-onto-ink);
}

.skp-onto__search .select2-container--default .select2-selection--single .select2-selection__placeholder {
  color: var(--skp-onto-ink-muted);
}

/* The theme's search glyph, same as the List view's submit button. */
.skp-onto__search .select2-container--default .select2-selection--single .select2-selection__arrow {
  top: 0;
  right: 0;
  width: 46px;
  height: 44px;
  background: url("data:image/svg+xml;charset=utf-8,%3Csvg width='14' height='14' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='m13 13-2.9-2.9m1.567-3.767A5.333 5.333 0 1 1 1 6.333a5.333 5.333 0 0 1 10.667 0Z' stroke='%2300abf1' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat center;
}

.skp-onto__search .select2-container--default .select2-selection--single .select2-selection__arrow b {
  display: none;
}

.skp-onto__search .select2-container--default .select2-selection--single .select2-selection__clear {
  margin-right: 6px;
  font-size: 18px;
  font-weight: 400;
  color: var(--skp-onto-ink-muted);
}

.skp-onto__search .select2-dropdown {
  overflow: hidden;
  border-color: var(--skp-onto-search-border);
  border-radius: 16px;
}

/* select2 also squares off, and drops the border on, the dropdown's side that
   meets the box; with the gap it needs both back. */
.skp-onto__search .select2-container--open .select2-dropdown--below {
  margin-top: 6px;
  border-top: 1px solid var(--skp-onto-search-border);
  border-radius: 16px;
}

.skp-onto__search .select2-container--open .select2-dropdown--above {
  margin-top: -6px;
  border-bottom: 1px solid var(--skp-onto-search-border);
  border-radius: 16px;
}

.skp-onto__search .select2-search--dropdown {
  padding: 10px;
}

.skp-onto__search .select2-search--dropdown .select2-search__field {
  height: 38px;
  padding: 0 14px;
  border: 1px solid var(--skp-onto-search-border);
  border-radius: 999px;
  font: inherit;
  outline: none;
}

.skp-onto__search .select2-search--dropdown .select2-search__field:focus {
  border-color: var(--skp-onto-search-focus);
}

.skp-onto__search .select2-results__option {
  padding: 8px 22px;
}

.skp-onto__search .select2-container--default .select2-results__option--highlighted[aria-selected] {
  background-color: #e6f2fb;
  color: #12557f;
}

.skp-onto__search .select2-container--default .select2-results__option[aria-selected="true"] {
  background-color: #f4f6f7;
  color: var(--skp-onto-ink);
  font-weight: 500;
}

/* ---- container breakpoints ---------------------------------------------
   Three steps, all keyed on the block's own width. */

/* Tablet-ish, or a half-width column on a desktop. */
@container skp-onto (max-width: 900px) {
  .skp-onto__frame {
    --skp-onto-inset: 16px;
    --skp-onto-title: 18px;
  }
}

/* Tighter chrome and a shorter frame. */
@container skp-onto (max-width: 640px) {
  .skp-onto__frame {
    --skp-onto-inset: 12px;
    --skp-onto-title: 16px;

    height: max(320px, min(68dvh, 640px));
    border-radius: 12px;
  }

  .skp-onto__search {
    width: 100%;
    margin-bottom: 12px;
  }
}

/* Phone width. */
@container skp-onto (max-width: 420px) {
  .skp-onto__frame {
    height: max(300px, min(64dvh, 560px));
  }

  .skp-onto__hud {
    font-size: 11px;
    max-width: calc(100% - var(--skp-onto-inset) * 2 - 96px);
  }
}

/* ---- touch -------------------------------------------------------------
   There is no hover on a touch screen, so the definition tooltip and the
   "tap again" hint never appear. The hud carries the affordance instead (see
   OntologyExplorer.announceFocus), and the targets grow. */
@media (hover: none) {
  .skp-onto__zoom button {
    width: 44px;
    height: 44px;
  }

  .skp-onto__hud {
    color: var(--skp-onto-ink);
  }
}

/* ---- term dialog -------------------------------------------------------
   The modal is core's ajax dialog holding the glossary term's full display, so
   its contents are the theme's business. These rules only shape the shell. */

.ui-dialog.skp-onto-dialog {
  border: 0;
  border-radius: 14px;
  box-shadow: 0 18px 60px rgba(18, 38, 63, 0.28);
  padding: 0;
  overflow: hidden;
  max-width: calc(100vw - 24px);
  font-family: Lexend, system-ui, sans-serif;
  /* jQuery UI parks dialogs at `.ui-front { z-index: 100 }`, which loses to
     everything this site puts over the page: the sticky navbar (--z-fixed:
     120), the theme's own modal layer (--z-modal: 180), the admin toolbar
     (501), lightgallery (510) and the mobile sidebar (1000, 10001 for its
     toggle). The term modal opened UNDER the header. Clear all of them rather
     than joining the theme's modal layer, which would still lose to the
     toolbar. The backdrop needs no rule of its own — jQuery UI gives
     .ui-widget-overlay an inline z-index of the dialog's minus one. */
  z-index: 10010;
}

.ui-dialog.skp-onto-dialog .ui-dialog-titlebar {
  padding: 26px 34px 0;
  border: 0;
  background: #fff;
}

.ui-dialog.skp-onto-dialog .ui-dialog-title {
  font-size: clamp(18px, 4vw, 23px);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.25;
  color: var(--skp-onto-ink, #12263f);
}

.ui-dialog.skp-onto-dialog .ui-dialog-titlebar-close {
  right: 32px;
  width: 24px;
  height: 24px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--skp-onto-ink, #12263f);
}

/* jQuery UI paints this from a bitmap sprite (ui-icon-closethick) sized for
   its own 16px icon grid. Swapped for an inline SVG matching the comp's
   close glyph exactly, masked so it follows the button's `color` instead of
   shipping its own fill. */
.ui-dialog.skp-onto-dialog .ui-dialog-titlebar-close .ui-icon {
  width: 24px;
  height: 24px;
  margin: -12px 0 0 -12px;
  background-color: currentColor;
  background-image: none;
  mask: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M5 5L19 19M19 5L5 19' stroke='%23000' stroke-width='2' stroke-linecap='square'/%3E%3C/svg%3E") no-repeat center / contain;
  -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M5 5L19 19M19 5L5 19' stroke='%23000' stroke-width='2' stroke-linecap='square'/%3E%3C/svg%3E") no-repeat center / contain;
}

.ui-dialog.skp-onto-dialog .ui-dialog-titlebar-close:hover {
  background: #f4f7f9;
}

.ui-dialog.skp-onto-dialog .ui-dialog-titlebar-close:focus-visible {
  outline: 2px solid #00527b;
  outline-offset: 2px;
}

.ui-dialog.skp-onto-dialog .ui-dialog-content {
  padding: 16px 34px 34px;
  background: #fff;
}

@media (max-width: 640px) {
  .ui-dialog.skp-onto-dialog .ui-dialog-titlebar {
    padding: 18px 20px 0;
  }

  .ui-dialog.skp-onto-dialog .ui-dialog-content {
    padding: 12px 20px 20px;
  }
}

/* The fallback shown when a term's page cannot be rendered. Deliberately plain:
   it is a dead end, not a record. */
.skp-onto-empty {
  padding: 4px 0 8px;
  font-size: 15px;
  line-height: 1.6;
  color: var(--skp-onto-ink, #12263f);
}
