2026, мистика, 18+
    Kindred Spirits

    Kindred Spirits

    Информация о пользователе

    Привет, Гость! Войдите или зарегистрируйтесь.


    Вы здесь » Kindred Spirits » Информация о мире » Локации Академии


    Локации Академии

    Сообщений 1 страница 2 из 2

    1

    Локации Академии

    Академия находится в Салеме, что севернее Бостона. Её кампус раскинулся на острове Уинтер, узкой и вытянутой вдоль океана земле в восточной части города с солёным ветром и испещрённую дорожками, которые то уходят в тень деревьев, то резко выводят к камням и воде. Здесь постоянно слышно море: оно обволакивает берег, приносит ветер и иногда окутывает всё вязким туманом.[float=right]https://upforme.ru/uploads/001c/82/f2/4/102066.png
    42.529617251361515, -70.868893210953[/float]

    Для простых людей это место известно как частное образовательное учреждение — «Салемский подготовительный колледж», в инфраструктуру которого входят яхтовый клуб и здания бывшего морского исследовательского центра Cat Cove. Для одарённых же это место в котором они могут находить друг друга и развивать свои магические таланты.

    Кампус разделён на несколько функциональных зон, соединённых дорогами, пешеходными маршрутами и служебными проездами. Основными ориентирами служат береговая линия на востоке острова, здание Главного корпуса в его южной части, а в северной зоне расположившиеся там мужское и женское общежития студентов. Западный сектор, находящийся на материке, занимает административно-служебный комплекс Академии в зданиях бывшего центра морских исследований Cat Cove.

    [html]
    <script src="https://feather-tail.github.io/MyBB-scripts-bundle/js/theme-switcher/theme-iframe.js"></script>
    <script src="https://feather-tail.github.io/MyBB-scripts-bundle/js/font-resizer/font-resizer-iframe.js"></script>
    <!doctype html>
    <html lang="ru">
    <head>
      <meta charset="utf-8" />
      <meta name="viewport" content="width=device-width,initial-scale=1" />
      <title>Карта кампуса</title>

      <link rel="preconnect" href="https://forumstatic.ru" crossorigin />
      <link rel="preload" href="https://forumstatic.ru/files/001c/82/f2/62594.svg" as="fetch" crossorigin />

      <style>
        :root{
          /* SETTINGS: размеры и поведение карты */
          --ks-map-height: clamp(520px, 70vh, 820px);
          --ks-map-ratio: 0.75595;
          --ks-map-frame-pad: 10px;

          /* SETTINGS: цвета рамки (градиент) */
          --ks-frame-grad-a: color-mix(in srgb, var(--accent, #566a7c) 55%, #fff);
          --ks-frame-grad-b: color-mix(in srgb, var(--accent2, #35597c) 45%, #fff);

          --ks-radius: var(--radius, 10px);
          --ks-gap: var(--gap, 16px);
          --ks-gap-sm: var(--small-gap, 8px);

          --ks-panel: var(--podform, #d4d4d5);
          --ks-panel-2: var(--panel-bg-light, var(--quote, #d1cfcf));
          --ks-border: var(--bord, rgba(0,0,0,.18));
          --ks-border-2: var(--panel-border, var(--ks-border));

          --ks-text: var(--text, #28323d);
          --ks-muted: var(--sec-text, #414952);

          --ks-accent: var(--accent, #566a7c);
          --ks-accent2: var(--accent2, #35597c);

          --ks-shadow: 0 10px 22px rgba(0,0,0,.12);
          --ks-shadow-strong: 0 16px 38px rgba(0,0,0,.16);

          --ks-map-bg: var(--htm-bg, none);
          --ks-map-frame: var(--pf-bg, none);

          --ks-hl-duration: 140ms;
          --ks-hl-brightness: 1.08;
          --ks-hl-saturate: 1.06;
          --ks-active-brightness: 1.14;
          --ks-active-saturate: 1.10;

          --ks-dim-opacity: .55;

          --ks-wash-opacity: .30;
          --ks-wash-focus-opacity: .40;

          --ks-dim-overlay: rgba(0,0,0,.16);
          --ks-dim-overlay-focus: rgba(0,0,0,.28);

          --ks-shell-pad: calc(var(--ks-gap) * 1.1);
          --ks-map-width: min(100%, calc(var(--ks-map-height) * var(--ks-map-ratio)));
        }

        *{ box-sizing:border-box; }

        body{
          margin:0;
          color: var(--ks-text);
          font: 14px/1.4 var(--main-font, system-ui), system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
          background: transparent;
        }

        .ks-icon{
          width: 16px;
          height: 16px;
          display:block;
          fill: currentColor;
        }

        .ks-map-shell{
          max-width: none;
          width: min(100%, calc(var(--ks-map-width) + var(--ks-shell-pad) * 2));
          margin: 0 auto;
          padding: var(--ks-shell-pad);
          border-radius: calc(var(--ks-radius) + 6px);
          background:
            linear-gradient(180deg, rgba(255,255,255,.55), rgba(255,255,255,.25)),
            var(--ks-map-bg);
          border: 1px solid color-mix(in srgb, var(--ks-border) 80%, transparent);
          box-shadow: var(--ks-shadow);
          position: relative;
          overflow: hidden;
        }

        .ks-map-shell::before{
          content:"";
          position:absolute;
          inset:0;
          background:
            radial-gradient(820px 300px at 18% 8%, color-mix(in srgb, var(--ks-accent) 18%, transparent), transparent 60%),
            radial-gradient(760px 300px at 82% 0%, color-mix(in srgb, var(--ks-accent2) 14%, transparent), transparent 58%),
            linear-gradient(180deg, rgba(255,255,255,.24), rgba(255,255,255,0));
          pointer-events:none;
          opacity:.9;
        }

        .ks-map-shell__inner{
          position:relative;
          z-index:1;
        }

        .ks-head{
          width: var(--ks-map-width);
          margin: 0 auto var(--ks-gap-sm);
          display:flex;
          justify-content:center;
          text-align:center;
        }

        .ks-title{
          margin:0;
          font-family: var(--sec-font, var(--main-font, inherit));
          font-size: 18px;
          letter-spacing:.2px;
          color: var(--ks-text);
        }

        .ks-toolbar{
          width: var(--ks-map-width);
          margin: 10px auto 14px;
          display:flex;
          gap: var(--ks-gap-sm);
          align-items:center;
          flex-wrap:wrap;
        }

        .ks-search{
          flex: 1 1 auto;
          min-width: 0;
          position:relative;
        }

        .ks-search__icon{
          position:absolute;
          left: 11px;
          top: 50%;
          transform: translateY(-50%);
          color: color-mix(in srgb, var(--ks-muted) 70%, transparent);
          pointer-events:none;
        }

        .ks-search__clear{
          position:absolute;
          right: 8px;
          top: 50%;
          transform: translateY(-50%);
          width: 32px;
          height: 32px;
          border-radius: 10px;
          border: 1px solid color-mix(in srgb, var(--ks-border-2) 85%, transparent);
          background:
            linear-gradient(180deg, rgba(255,255,255,.65), rgba(255,255,255,.35)),
            var(--ks-panel-2);
          color: color-mix(in srgb, var(--ks-muted) 80%, transparent);
          cursor:pointer;
          box-shadow: 0 8px 16px rgba(0,0,0,.10);
          display:none;
          align-items:center;
          justify-content:center;
          transition: transform 120ms ease, background 120ms ease, color 120ms ease;
        }
        .ks-search__clear:hover{
          transform: translateY(-50%) translateY(-1px);
          color: color-mix(in srgb, var(--ks-text) 85%, transparent);
          background: linear-gradient(180deg, color-mix(in srgb, var(--ks-accent) 20%, #fff), rgba(255,255,255,.45));
        }

        .ks-search input{
          width:100%;
          padding: 10px 44px 10px 36px;
          border-radius: var(--ks-radius);
          border: 1px solid color-mix(in srgb, var(--ks-border-2) 85%, transparent);
          background:
            linear-gradient(180deg, rgba(255,255,255,.6), rgba(255,255,255,.35)),
            var(--ks-panel-2);
          color: var(--ks-text);
          outline:none;
          box-shadow: 0 8px 18px rgba(0,0,0,.10);
          transition: border-color 140ms ease, box-shadow 140ms ease;
        }
        .ks-search input::placeholder{ color: color-mix(in srgb, var(--ks-muted) 70%, transparent); }
        .ks-search input:focus{
          border-color: color-mix(in srgb, var(--ks-accent) 70%, var(--ks-border-2));
          box-shadow: 0 10px 22px color-mix(in srgb, var(--ks-accent) 22%, rgba(0,0,0,.10));
        }

        .ks-searchResults{
          position:absolute;
          top: calc(100% + 8px);
          left:0;
          right:0;
          z-index: 40;
          border-radius: var(--ks-radius);
          border: 1px solid color-mix(in srgb, var(--ks-border-2) 85%, transparent);
          background:
            linear-gradient(180deg, rgba(255,255,255,.78), rgba(255,255,255,.55)),
            var(--ks-panel-2);
          box-shadow: var(--ks-shadow-strong);
          overflow:hidden;
          backdrop-filter: blur(6px);
        }
        .ks-searchResults[hidden]{ display:none; }

        .ks-searchItem{
          width:100%;
          text-align:left;
          padding: 10px 12px;
          background: transparent;
          border:0;
          color: var(--ks-text);
          cursor:pointer;
          display:flex;
          align-items:center;
          gap: 10px;
          font: inherit;
          transition: background 120ms ease;
        }
        .ks-searchItem:hover{
          background: color-mix(in srgb, var(--ks-accent) 12%, transparent);
        }
        .ks-searchItem small{
          display:block;
          margin-top:2px;
          color: var(--ks-muted);
        }

        .ks-map{
          width: var(--ks-map-width);
          margin: 0 auto;
          position:relative;
          padding: var(--ks-map-frame-pad);
          border-radius: calc(var(--ks-radius) + 10px);
          border: 2px solid transparent;
          background:
            linear-gradient(180deg, rgba(255,255,255,.42), rgba(255,255,255,.18)) padding-box,
            var(--ks-map-frame) padding-box,
            linear-gradient(135deg, var(--ks-frame-grad-a), var(--ks-frame-grad-b)) border-box;
          box-shadow: var(--ks-shadow-strong);
          overflow:hidden;
        }

        .ks-map::after{
          content:"";
          position:absolute;
          inset: 8px;
          border-radius: calc(var(--ks-radius) + 4px);
          pointer-events:none;
          box-shadow:
            inset 0 0 0 1px rgba(255,255,255,.35),
            inset 0 0 0 2px rgba(0,0,0,.06);
          z-index: 5;
        }

        .ks-map__viewport{
          position:relative;
          width:100%;
          height: var(--ks-map-height);
          background: rgba(255,255,255,.12);
          overflow:hidden;
          border-radius: calc(var(--ks-radius) + 6px);
        }

        .ks-map__viewport::before{
          content:"";
          position:absolute;
          inset:0;
          pointer-events:none;
          opacity: var(--ks-wash-opacity);
          z-index: 2;
          background:
            linear-gradient(180deg,
              color-mix(in srgb, var(--ks-accent) 26%, transparent),
              color-mix(in srgb, var(--ks-accent2) 20%, transparent)),
            radial-gradient(1200px 700px at 30% 25%,
              color-mix(in srgb, var(--ks-accent) 22%, transparent),
              transparent 62%),
            radial-gradient(1100px 650px at 70% 70%,
              color-mix(in srgb, var(--ks-accent2) 18%, transparent),
              transparent 60%);
          mix-blend-mode: multiply;
        }

        .ks-map__viewport::after{
          content:"";
          position:absolute;
          inset:0;
          pointer-events:none;
          background: var(--ks-dim-overlay);
          opacity: 0;
          transition: opacity 140ms ease, background 140ms ease;
          z-index: 3;
        }

        .ks-map.is-focus .ks-map__viewport::before{ opacity: var(--ks-wash-focus-opacity); }
        .ks-map.is-focus .ks-map__viewport::after{
          opacity: 1;
          background: var(--ks-dim-overlay-focus);
        }

        .ks-map__loading,
        .ks-map__error{
          position:absolute;
          inset:0;
          display:flex;
          align-items:center;
          justify-content:center;
          text-align:center;
          padding: 20px;
          color: var(--ks-muted);
          background: rgba(255,255,255,.35);
          backdrop-filter: blur(8px);
          z-index: 4;
        }

        .ks-map__viewport svg{
          width:100%;
          height:100%;
          display:block;
          user-select:none;
          -webkit-user-drag:none;
          position:relative;
          z-index: 1;
          transition: filter 140ms ease, opacity 140ms ease;
          filter: grayscale(0.5);
        }

        .ks-map.is-focus .ks-map__viewport svg{
          opacity: var(--ks-dim-opacity);
          filter: grayscale(0.5) saturate(.92) brightness(.93) contrast(1.02);
        }

        .ks-map__hotspot-target{
          transition: filter var(--ks-hl-duration) ease, opacity var(--ks-hl-duration) ease;
        }

        .ks-map__hotspot-target.is-hovered{
          filter:
            brightness(var(--ks-hl-brightness))
            saturate(var(--ks-hl-saturate))
            drop-shadow(0 6px 14px rgba(0,0,0,.18))
            drop-shadow(0 0 14px color-mix(in srgb, var(--ks-accent) 55%, transparent));
          opacity: 1;
        }

        .ks-map__hotspot-target.is-active{
          filter:
            brightness(var(--ks-active-brightness))
            saturate(var(--ks-active-saturate))
            drop-shadow(0 12px 20px rgba(0,0,0,.22))
            drop-shadow(0 0 18px color-mix(in srgb, var(--ks-accent2) 55%, transparent));
          opacity: 1;
        }

        @media (prefers-reduced-motion: reduce){
          .ks-map__hotspot-target{ transition:none; }
          .ks-map__viewport svg{ transition:none; }
          .ks-map__viewport::after{ transition:none; }
        }

        .ks-tooltip{
          position: fixed;
          z-index: 60;
          max-width: min(460px, calc(100vw - 18px));
          left: 0;
          top: 0;
          transform: translate3d(0,0,0);
          border-radius: calc(var(--ks-radius) + 6px);
          border: 1px solid color-mix(in srgb, var(--ks-border-2) 85%, transparent);
          background:
            linear-gradient(180deg, rgba(255,255,255,.86), rgba(255,255,255,.64)),
            var(--ks-panel-2);
          box-shadow: var(--ks-shadow-strong);
          color: var(--ks-text);
          backdrop-filter: blur(10px);
          pointer-events: auto;
        }
        .ks-tooltip[hidden]{ display:none; }

        .ks-tooltip__inner{ padding: 12px; }

        .ks-tooltip__top{
          display:flex;
          align-items:flex-start;
          justify-content:space-between;
          gap:10px;
        }

        .ks-tooltip__title{
          margin:0;
          font-size: 13px;
          font-weight: 750;
          letter-spacing: .2px;
          font-family: var(--sec-font, var(--main-font, inherit));
          color: var(--ks-text);
          line-height: 1.25;
        }

        .ks-tooltip__close{
          appearance:none;
          border: 1px solid color-mix(in srgb, var(--ks-border-2) 85%, transparent);
          background: linear-gradient(180deg, color-mix(in srgb, var(--ks-accent) 22%, #fff), rgba(255,255,255,.55));
          color: color-mix(in srgb, var(--ks-text) 88%, transparent);
          line-height: 1;
          padding: 7px 9px;
          cursor:pointer;
          border-radius: 10px;
          box-shadow: 0 8px 16px rgba(0,0,0,.10);
          transition: transform 120ms ease, background 120ms ease, color 120ms ease;
          flex: 0 0 auto;
          display:flex;
          align-items:center;
          justify-content:center;
        }
        .ks-tooltip__close:hover{
          transform: translateY(-1px);
          color: var(--ks-text);
          background: linear-gradient(180deg, color-mix(in srgb, var(--ks-accent) 32%, #fff), rgba(255,255,255,.60));
        }

        .ks-tooltip__body{
          margin-top: 10px;
          display:grid;
          grid-template-columns: 96px 1fr;
          gap: 10px;
          align-items:start;
        }

        .ks-tooltip__img{
          width: 96px;
          height: 96px;
          border-radius: 12px;
          border: 1px solid color-mix(in srgb, var(--ks-border-2) 85%, transparent);
          object-fit: cover;
          background:
            linear-gradient(180deg, rgba(255,255,255,.50), rgba(255,255,255,.20)),
            var(--ks-panel);
          display:block;
          box-shadow: 0 10px 18px rgba(0,0,0,.10);
        }

        .ks-tooltip__desc{
          margin:0;
          font-size: 12px;
          color: color-mix(in srgb, var(--ks-text) 86%, transparent);
        }

        .ks-tooltip__more{
          display:inline-block;
          margin-top: 8px;
          font-size: 12px;
          color: color-mix(in srgb, var(--ks-accent2) 85%, var(--ks-text));
          text-decoration: none;
          border-bottom: 1px dashed color-mix(in srgb, var(--ks-accent2) 45%, transparent);
        }
        .ks-tooltip__more:hover{
          border-bottom-style: solid;
        }

        .ks-tooltip[data-mode="preview"] .ks-tooltip__close{ display:none; }
        .ks-tooltip[data-mode="preview"] .ks-tooltip__body{ display:none; }
        .ks-tooltip[data-mode="preview"] .ks-tooltip__inner{ padding: 10px 12px; }

        @media (max-width: 720px){
          .ks-map-shell{ width: 100%; }
          .ks-head, .ks-toolbar, .ks-map{ width: 100%; }
          .ks-map__viewport{
            height: auto;
            aspect-ratio: 3431.52 / 4539.36;
          }
        }
      </style>
    </head>

    <body>
      <section class="ks-map-shell">
        <div class="ks-map-shell__inner">
          <header class="ks-head">
            <h1 class="ks-title">Карта кампуса</h1>
          </header>

          <div class="ks-toolbar">
            <div class="ks-search">
              <span class="ks-search__icon" aria-hidden="true">
                <svg class="ks-icon" viewBox="0 0 24 24" aria-hidden="true">
                  <path d="M10 4a6 6 0 1 1 0 12a6 6 0 0 1 0-12m0-2a8 8 0 1 0 4.9 14.3l4.4 4.4a1 1 0 0 0 1.4-1.4l-4.4-4.4A8 8 0 0 0 10 2Z"/>
                </svg>
              </span>
              <input id="mapSearch" type="search" placeholder="Поиск по объектам…" autocomplete="off" />
              <button class="ks-search__clear" id="mapSearchClear" type="button" aria-label="Очистить поиск">
                <svg class="ks-icon" viewBox="0 0 24 24" aria-hidden="true">
                  <path d="M18.3 5.7a1 1 0 0 0-1.4 0L12 10.6L7.1 5.7A1 1 0 0 0 5.7 7.1L10.6 12l-4.9 4.9a1 1 0 1 0 1.4 1.4l4.9-4.9l4.9 4.9a1 1 0 0 0 1.4-1.4L13.4 12l4.9-4.9a1 1 0 0 0 0-1.4Z"/>
                </svg>
              </button>
              <div class="ks-searchResults" id="mapSearchResults" hidden></div>
            </div>
          </div>

          <div class="ks-map" id="mapRoot">
            <div class="ks-map__viewport" id="mapViewport">
              <div class="ks-map__loading" id="mapLoading">Карта загрузится, когда дойдёшь до неё…</div>
            </div>
          </div>
        </div>
      </section>

      <div class="ks-tooltip" id="mapTooltip" hidden data-mode="preview" role="dialog" aria-modal="false">
        <div class="ks-tooltip__inner">
          <div class="ks-tooltip__top">
            <div style="min-width:0;">
              <p class="ks-tooltip__title" id="tipTitle">—</p>
            </div>
            <button class="ks-tooltip__close" id="tipClose" aria-label="Закрыть">
              <svg class="ks-icon" viewBox="0 0 24 24" aria-hidden="true">
                <path d="M18.3 5.7a1 1 0 0 0-1.4 0L12 10.6L7.1 5.7A1 1 0 0 0 5.7 7.1L10.6 12l-4.9 4.9a1 1 0 1 0 1.4 1.4l4.9-4.9l4.9 4.9a1 1 0 0 0 1.4-1.4L13.4 12l4.9-4.9a1 1 0 0 0 0-1.4Z"/>
              </svg>
            </button>
          </div>

          <div class="ks-tooltip__body">
            <img class="ks-tooltip__img" id="tipImg" alt="" />
            <div>
              <p class="ks-tooltip__desc" id="tipDesc">—</p>
              <a class="ks-tooltip__more" id="tipMore" href="#" target="_blank" rel="noopener noreferrer" hidden>Читать далее…</a>
            </div>
          </div>
        </div>
      </div>

      <div id="mapData" hidden>
        <div
          data-map-id="_Слой_2_Изображение"
          data-title="Главное здание"
          data-desc="Главное здание Академии расположено в южной части острова, ближе к открытому побережью. Его архитектура сочетает массивные каменные конструкции и современные элементы: стекло, металл, строгие линии фасада."
          data-img="https://forumstatic.ru/files/001c/8d/fd/24675.png"
          data-url="https://kindredspirits.ru/viewtopic.php?id=84#p1110"
        ></div>

        <div
          data-map-id="_Слой_3_Изображение"
          data-title="Медицинский корпус"
          data-desc="Медицинский центр в салемском кампусе куда уместнее было бы называть небольшим медицинским центром. Он представляет из себя отдельное здание в западной части острова, неподалёку от КПП и общежитий."
          data-img="https://forumstatic.ru/files/001c/8d/fd/24675.png"
          data-url="https://kindredspirits.ru/viewtopic.php?id=84#p1122"
        ></div>

        <div
          data-map-id="_Слой_4_Изображение"
          data-title="Мужское общежитие"
          data-desc="Жилые корпуса студентов находятся в северной части острова, ближе к въезду и внешней инфраструктуре кампуса. Такое расположение позволяет отделить учебные и жилые зоны, сохраняя при этом удобную связь между ними. Общежития стоят чуть в стороне от оживлённых маршрутов и окружены зелёными участками, создающими более спокойную и камерную атмосферу."
          data-img="https://forumstatic.ru/files/001c/8d/fd/24675.png"
          data-url="https://kindredspirits.ru/viewtopic.php?id=84#p1115"
        ></div>

        <div
          data-map-id="_Слой_12_Изображение"
          data-title="Женское общежитие"
          data-desc="Жилые корпуса студентов находятся в северной части острова, ближе к въезду и внешней инфраструктуре кампуса. Такое расположение позволяет отделить учебные и жилые зоны, сохраняя при этом удобную связь между ними. Общежития стоят чуть в стороне от оживлённых маршрутов и окружены зелёными участками, создающими более спокойную и камерную атмосферу."
          data-img="https://forumstatic.ru/files/001c/8d/fd/24675.png"
          data-url="https://kindredspirits.ru/viewtopic.php?id=84#p1115"
        ></div>

        <div
          data-map-id="_Слой_5_Изображение"
          data-title="КПП"
          data-desc="Основной доступ на территорию кампуса осуществляется через северный въезд со стороны материка. Дорога выводит к контрольно-пропускному пункту..."
          data-img="https://forumstatic.ru/files/001c/8d/fd/24675.png"
          data-url="https://kindredspirits.ru/viewtopic.php?id=84#p1111"
        ></div>

        <div
          data-map-id="_Слой_6_Изображение"
          data-title="Здание Службы безопасности"
          data-desc="Здания бывшего университетского комплекса Cat Cove используются как административно-служебная зона Академии. Здесь размещаются подразделения службы безопасности, технические службы и центры связи."
          data-img="https://forumstatic.ru/files/001c/8d/fd/24675.png"
          data-url="https://kindredspirits.ru/viewtopic.php?id=84#p1121"
        ></div>
      </div>

      <script>
        const SETTINGS = {
          // SETTINGS: ссылка на SVG карты
          svgUrl: 'https://forumstatic.ru/files/001c/82/f2/62594.svg',
          // SETTINGS: расширение зоны клика вокруг объекта (px)
          hitPadding: 10,
          // SETTINGS: отступ тултипа от якоря (px)
          tooltipOffset: 12,
          // SETTINGS: отступ от краёв экрана при размещении тултипа (px)
          edgePad: 10,
          // SETTINGS: long-press для тача (ms)
          longPressMs: 480,
          // SETTINGS: допуск движения при long-press (px)
          longPressMovePx: 10,
          // SETTINGS: максимум результатов поиска
          searchMaxItems: 7,
          // SETTINGS: насколько заранее грузить карту до попадания в viewport
          lazyRootMargin: '300px'
        };

        const PLACEHOLDER_IMG =
          'data:image/svg+xml;charset=utf-8,' +
          encodeURIComponent(
            '<svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" viewBox="0 0 192 192">' +
            '<defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="1">' +
            '<stop offset="0" stop-color="#cfe1f3"/><stop offset="1" stop-color="#bfc8d0"/>' +
            '</linearGradient></defs>' +
            '<rect width="192" height="192" rx="28" fill="url(#g)"/>' +
            '<path d="M52 88l44-34 44 34v50a8 8 0 0 1-8 8H60a8 8 0 0 1-8-8V88z" fill="rgba(0,0,0,0.10)"/>' +
            '<path d="M82 146V110h28v36" fill="rgba(0,0,0,0.14)"/>' +
            '<path d="M52 88l44-34 44 34" fill="none" stroke="rgba(0,0,0,0.18)" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>' +
            '</svg>'
          );

        const mapRoot = document.getElementById('mapRoot');
        const viewport = document.getElementById('mapViewport');
        const loading = document.getElementById('mapLoading');

        const tooltip = document.getElementById('mapTooltip');
        const tipTitle = document.getElementById('tipTitle');
        const tipClose = document.getElementById('tipClose');
        const tipImg = document.getElementById('tipImg');
        const tipDesc = document.getElementById('tipDesc');
        const tipMore = document.getElementById('tipMore');

        const searchInput = document.getElementById('mapSearch');
        const searchResults = document.getElementById('mapSearchResults');
        const searchClear = document.getElementById('mapSearchClear');

        const escapeCss = (s) => (window.CSS && typeof CSS.escape === 'function')
          ? CSS.escape(s)
          : String(s).replace(/([ !"#$%&'()*+,.\/:;<=>?@[\\\]^`{|}~])/g, '\\$1');

        const clamp = (v, a, b) => Math.max(a, Math.min(b, v));

        function parseHotspotsFromData(){
          const nodes = Array.from(document.querySelectorAll('#mapData [data-map-id]'));
          return nodes.map((n) => ({
            id: n.dataset.mapId || '',
            title: n.dataset.title || '',
            desc: n.dataset.desc || '',
            img: n.dataset.img || '',
            url: n.dataset.url || ''
          })).filter((x) => x.id && x.title);
        }

        function sanitizeSvgText(svgText){
          const parser = new DOMParser();
          const doc = parser.parseFromString(svgText, 'image/svg+xml');
          const svg = doc.documentElement;

          Array.from(svg.querySelectorAll('script')).forEach((n) => n.remove());
          Array.from(svg.querySelectorAll('foreignObject')).forEach((n) => n.remove());

          const all = svg.querySelectorAll('*');
          for (const el of all){
            const attrs = Array.from(el.attributes);
            for (const a of attrs){
              if (/^on/i.test(a.name)) el.removeAttribute(a.name);
            }
          }
          return svg.outerHTML;
        }

        function svgEl(tag){
          return document.createElementNS('http://www.w3.org/2000/svg', tag);
        }

        function closestHotspot(node){
          if (!node) return null;
          if (node.closest) return node.closest('[data-map-id]');
          let cur = node;
          while (cur && cur.getAttribute){
            if (cur.getAttribute('data-map-id')) return cur;
            cur = cur.parentNode;
          }
          return null;
        }

        function setTooltipContent(data, mode){
          tooltip.dataset.mode = mode;
          tipTitle.textContent = data.title || '—';
          tipDesc.textContent = data.desc || '';
          tipImg.src = data.img || PLACEHOLDER_IMG;
          tipImg.alt = data.title || '';

          if (data.url){
            tipMore.href = data.url;
            tipMore.hidden = false;
          } else {
            tipMore.hidden = true;
            tipMore.removeAttribute('href');
          }
        }

        let tipMetrics = { mode: '', w: 0, h: 0, dirty: true };

        function markTipDirty(){
          tipMetrics.dirty = true;
        }

        function updateTipMetrics(mode){
          if (!tipMetrics.dirty && tipMetrics.mode === mode && tipMetrics.w && tipMetrics.h) return;

          tipMetrics.mode = mode;
          tipMetrics.dirty = false;

          const prevVis = tooltip.style.visibility;
          const prevLeft = tooltip.style.left;
          const prevTop = tooltip.style.top;

          tooltip.style.visibility = 'hidden';
          tooltip.style.left = '-9999px';
          tooltip.style.top = '-9999px';

          const r = tooltip.getBoundingClientRect();
          tipMetrics.w = r.width;
          tipMetrics.h = r.height;

          tooltip.style.visibility = prevVis || '';
          tooltip.style.left = prevLeft || '0px';
          tooltip.style.top = prevTop || '0px';
        }

        function scorePlacement(left, top, w, h){
          const vpW = window.innerWidth;
          const vpH = window.innerHeight;
          const overflowL = Math.max(0, SETTINGS.edgePad - left);
          const overflowT = Math.max(0, SETTINGS.edgePad - top);
          const overflowR = Math.max(0, (left + w) - (vpW - SETTINGS.edgePad));
          const overflowB = Math.max(0, (top + h) - (vpH - SETTINGS.edgePad));
          return overflowL + overflowT + overflowR + overflowB;
        }

        function placeTooltipAt(anchorX, anchorY){
          const w = tipMetrics.w || tooltip.getBoundingClientRect().width;
          const h = tipMetrics.h || tooltip.getBoundingClientRect().height;
          const o = SETTINGS.tooltipOffset;

          const candidates = [
            { p: 'top', left: anchorX - w / 2, top: anchorY - h - o },
            { p: 'bottom', left: anchorX - w / 2, top: anchorY + o },
            { p: 'right', left: anchorX + o, top: anchorY - h / 2 },
            { p: 'left', left: anchorX - w - o, top: anchorY - h / 2 }
          ];

          let best = candidates[0];
          let bestScore = Infinity;

          for (const c of candidates){
            const s = scorePlacement(c.left, c.top, w, h);
            if (s < bestScore){
              bestScore = s;
              best = c;
            }
          }

          const vpW = window.innerWidth;
          const vpH = window.innerHeight;

          const left = clamp(best.left, SETTINGS.edgePad, vpW - SETTINGS.edgePad - w);
          const top = clamp(best.top, SETTINGS.edgePad, vpH - SETTINGS.edgePad - h);

          tooltip.style.left = left + 'px';
          tooltip.style.top = top + 'px';
          tooltip.hidden = false;
          tooltip.dataset.placement = best.p;
        }

        function hideTooltip(){
          tooltip.hidden = true;
          tooltip.style.left = '0px';
          tooltip.style.top = '0px';
        }

        let svgRoot = null;
        let activeTarget = null;
        let pinnedOpen = false;
        let previewOpen = false;

        const idToTarget = new Map();

        function setHovered(target, on){
          if (!target) return;
          target.classList.toggle('is-hovered', !!on);
        }

        function setActive(target, on){
          if (!target) return;
          target.classList.toggle('is-active', !!on);
        }

        function clearActive(){
          if (activeTarget){
            setActive(activeTarget, false);
            activeTarget = null;
          }
          mapRoot.classList.remove('is-focus');
        }

        function openPreview(data, x, y){
          if (pinnedOpen) return;
          previewOpen = true;
          setTooltipContent(data, 'preview');
          tooltip.hidden = false;
          markTipDirty();
          updateTipMetrics('preview');
          placeTooltipAt(x, y);
        }

        function closePreview(){
          if (!previewOpen) return;
          previewOpen = false;
          hideTooltip();
        }

        function openPinned(data, target, x, y){
          pinnedOpen = true;
          previewOpen = false;

          mapRoot.classList.add('is-focus');

          setTooltipContent(data, 'pinned');
          tooltip.hidden = false;
          markTipDirty();
          updateTipMetrics('pinned');

          if (activeTarget && activeTarget !== target) setActive(activeTarget, false);
          activeTarget = target;
          setActive(activeTarget, true);

          placeTooltipAt(x, y);
        }

        function closePinned(){
          if (!pinnedOpen) return;
          pinnedOpen = false;
          hideTooltip();
          clearActive();
        }

        function togglePinned(data, target, x, y){
          if (pinnedOpen && activeTarget === target){
            closePinned();
            return;
          }
          openPinned(data, target, x, y);
        }

        function anchorFromTarget(target){
          const r = target.getBoundingClientRect();
          return { x: r.left + r.width / 2, y: r.top + r.height / 2 };
        }

        function attachHitRect(target, data){
          let bbox = null;
          try { bbox = target.getBBox(); } catch(e) { bbox = null; }
          if (!bbox) return null;

          const pad = SETTINGS.hitPadding;
          const rect = svgEl('rect');
          rect.setAttribute('x', String(bbox.x - pad));
          rect.setAttribute('y', String(bbox.y - pad));
          rect.setAttribute('width', String(bbox.width + pad * 2));
          rect.setAttribute('height', String(bbox.height + pad * 2));
          rect.setAttribute('fill', '#000');
          rect.setAttribute('fill-opacity', '0');
          rect.style.cursor = 'pointer';

          rect.dataset.mapId = data.id;
          rect.dataset.title = data.title;
          rect.dataset.desc = data.desc;
          rect.dataset.img = data.img;
          rect.dataset.url = data.url;

          target.classList.add('ks-map__hotspot-target');
          target.style.pointerEvents = 'none';

          const parent = target.parentNode;
          if (parent) parent.insertBefore(rect, target.nextSibling);

          return rect;
        }

        function getDataFromHotspotEl(hs){
          return {
            id: hs.dataset.mapId || '',
            title: hs.dataset.title || '',
            desc: hs.dataset.desc || '',
            img: hs.dataset.img || '',
            url: hs.dataset.url || ''
          };
        }

        function buildSearchUI(hotspots){
          const normalize = (s) => String(s || '').trim().toLowerCase();

          const closeList = () => { searchResults.hidden = true; searchResults.innerHTML = ''; };
          const openList = () => { searchResults.hidden = false; };

          const setClearVisible = () => {
            searchClear.style.display = searchInput.value ? 'flex' : 'none';
          };

          const computeMatches = () => {
            const q = normalize(searchInput.value);
            if (!q) return [];
            return hotspots
              .map((h) => ({ h, t: normalize(h.title), d: normalize(h.desc) }))
              .filter((x) => x.t.includes(q) || x.d.includes(q))
              .slice(0, SETTINGS.searchMaxItems)
              .map((x) => x.h);
          };

          const render = (items) => {
            if (!items.length) { closeList(); return; }
            openList();
            searchResults.innerHTML = items.map((it, i) => {
              const title = it.title.replace(/</g,'&lt;').replace(/>/g,'&gt;');
              const desc = (it.desc || '').replace(/</g,'&lt;').replace(/>/g,'&gt;');
              return (
                '<button class="ks-searchItem" type="button" data-idx="' + i + '">' +
                  '<div style="min-width:0;">' +
                    '<div style="white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">' + title + '</div>' +
                    (desc ? '<small style="white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">' + desc + '</small>' : '') +
                  '</div>' +
                '</button>'
              );
            }).join('');
          };

          const pick = (item) => {
            const target = idToTarget.get(item.id);
            if (!target) return;

            viewport.scrollIntoView({ behavior: 'smooth', block: 'center' });

            const a = anchorFromTarget(target);
            togglePinned(item, target, a.x, a.y);

            closeList();
            searchInput.blur();
          };

          searchInput.addEventListener('input', () => {
            setClearVisible();
            const q = normalize(searchInput.value);
            if (!q) { closeList(); return; }
            render(computeMatches());
          });

          searchInput.addEventListener('keydown', (e) => {
            if (e.key === 'Escape') { closeList(); return; }
            if (e.key === 'Enter') {
              const firstBtn = searchResults.querySelector('.ks-searchItem');
              if (firstBtn){
                firstBtn.click();
                e.preventDefault();
              }
            }
          });

          searchResults.addEventListener('click', (e) => {
            const btn = e.target.closest('.ks-searchItem');
            if (!btn) return;
            const idx = Number(btn.dataset.idx);
            const items = computeMatches();
            const item = items[idx];
            if (item) pick(item);
          });

          document.addEventListener('click', (e) => {
            if (!searchResults.hidden && !searchResults.contains(e.target) && e.target !== searchInput){
              closeList();
            }
          });

          searchClear.addEventListener('click', () => {
            searchInput.value = '';
            searchInput.focus();
            setClearVisible();
            closeList();
          });

          setClearVisible();
        }

        let rafMove = 0;
        let lastMoveX = 0;
        let lastMoveY = 0;

        function schedulePreviewMove(x, y){
          lastMoveX = x;
          lastMoveY = y;
          if (rafMove) return;
          rafMove = requestAnimationFrame(() => {
            rafMove = 0;
            if (previewOpen && !pinnedOpen && !tooltip.hidden){
              placeTooltipAt(lastMoveX, lastMoveY);
            }
          });
        }

        function bindDelegatedEvents(){
          let hoveredId = null;

          const clearHover = (id) => {
            if (!id) return;
            const t = idToTarget.get(id);
            setHovered(t, false);
          };

          svgRoot.addEventListener('pointerover', (e) => {
            if (e.pointerType !== 'mouse') return;
            if (pinnedOpen) return;

            const hs = closestHotspot(e.target);
            if (!hs) return;

            const id = hs.dataset.mapId || '';
            if (!id || id === hoveredId) return;

            if (hoveredId) clearHover(hoveredId);
            hoveredId = id;

            const target = idToTarget.get(id);
            setHovered(target, true);

            openPreview(getDataFromHotspotEl(hs), e.clientX, e.clientY);
          });

          svgRoot.addEventListener('pointerout', (e) => {
            if (e.pointerType !== 'mouse') return;
            if (pinnedOpen) return;

            const from = closestHotspot(e.target);
            if (!from) return;

            const to = closestHotspot(e.relatedTarget);
            if (to && to.dataset.mapId === from.dataset.mapId) return;

            const id = from.dataset.mapId || '';
            if (id && id === hoveredId){
              clearHover(hoveredId);
              hoveredId = null;
            }

            closePreview();
          });

          svgRoot.addEventListener('pointermove', (e) => {
            if (e.pointerType !== 'mouse') return;
            if (!previewOpen || pinnedOpen) return;
            schedulePreviewMove(e.clientX, e.clientY);
          });

          svgRoot.addEventListener('click', (e) => {
            const hs = closestHotspot(e.target);
            if (!hs) return;

            e.stopPropagation();

            const id = hs.dataset.mapId || '';
            const target = idToTarget.get(id);
            if (!target) return;

            togglePinned(getDataFromHotspotEl(hs), target, e.clientX, e.clientY);
          });

          let press = null;

          const clearPress = () => {
            if (press && press.timer) clearTimeout(press.timer);
            press = null;
          };

          svgRoot.addEventListener('pointerdown', (e) => {
            if (e.pointerType === 'mouse') return;

            const hs = closestHotspot(e.target);
            if (!hs) return;

            const id = hs.dataset.mapId || '';
            if (!id) return;

            press = {
              id,
              startX: e.clientX,
              startY: e.clientY,
              fired: false,
              timer: setTimeout(() => {
                if (!press) return;
                press.fired = true;
                openPreview(getDataFromHotspotEl(hs), e.clientX, e.clientY);
              }, SETTINGS.longPressMs)
            };
          }, { passive: true });

          svgRoot.addEventListener('pointermove', (e) => {
            if (!press) return;
            const dx = e.clientX - press.startX;
            const dy = e.clientY - press.startY;
            if (Math.hypot(dx, dy) > SETTINGS.longPressMovePx){
              clearPress();
            }
          }, { passive: true });

          svgRoot.addEventListener('pointerup', (e) => {
            if (!press) return;

            const hs = closestHotspot(e.target);
            const id = press.id;
            const fired = press.fired;

            clearPress();

            if (fired){
              closePreview();
              return;
            }

            if (!hs) return;
            if ((hs.dataset.mapId || '') !== id) return;

            const target = idToTarget.get(id);
            if (!target) return;

            togglePinned(getDataFromHotspotEl(hs), target, e.clientX, e.clientY);
          });

          svgRoot.addEventListener('pointercancel', () => {
            clearPress();
            closePreview();
          });
        }

        async function loadMap(){
          try{
            const hotspots = parseHotspotsFromData();

            const res = await fetch(SETTINGS.svgUrl, { cache: 'force-cache' });
            if (!res.ok) throw new Error('HTTP ' + res.status);

            const raw = await res.text();
            const cleaned = sanitizeSvgText(raw);

            viewport.innerHTML = cleaned;
            svgRoot = viewport.querySelector('svg');
            if (!svgRoot) throw new Error('SVG не найден');

            svgRoot.setAttribute('preserveAspectRatio', 'xMidYMid meet');

            const misses = [];

            for (const h of hotspots){
              const target = svgRoot.querySelector('#' + escapeCss(h.id));
              if (!target){
                misses.push(h.id);
                continue;
              }

              idToTarget.set(h.id, target);

              const hit = attachHitRect(target, h);
              if (!hit){
                target.dataset.mapId = h.id;
                target.dataset.title = h.title;
                target.dataset.desc = h.desc;
                target.dataset.img = h.img;
                target.dataset.url = h.url;
                target.classList.add('ks-map__hotspot-target');
                target.style.cursor = 'pointer';
              }
            }

            buildSearchUI(hotspots);
            bindDelegatedEvents();

            tipImg.addEventListener('error', () => { tipImg.src = PLACEHOLDER_IMG; });

            tipClose.addEventListener('click', (e) => {
              e.stopPropagation();
              closePinned();
            });

            tooltip.addEventListener('click', (e) => e.stopPropagation());

            viewport.addEventListener('click', () => {
              closePinned();
              closePreview();
            });

            window.addEventListener('keydown', (e) => {
              if (e.key === 'Escape'){
                closePinned();
                closePreview();
                searchResults.hidden = true;
              }
            });

            window.addEventListener('resize', () => {
              markTipDirty();
              if (!tooltip.hidden && pinnedOpen && activeTarget){
                updateTipMetrics('pinned');
                const a = anchorFromTarget(activeTarget);
                placeTooltipAt(a.x, a.y);
              }
            }, { passive: true });

            if (loading) loading.remove();

            if (misses.length){
              const warn = document.createElement('div');
              warn.className = 'ks-map__error';
              warn.textContent = 'Часть объектов не найдена по ID: ' + misses.join(', ');
              viewport.appendChild(warn);
              setTimeout(() => warn.remove(), 3800);
            }
          } catch (err){
            viewport.innerHTML = '';
            const box = document.createElement('div');
            box.className = 'ks-map__error';
            box.textContent = 'Не удалось загрузить карту. Проверь доступность SVG по ссылке и CORS.';
            viewport.appendChild(box);
          }
        }

        function initLazy(){
          let loaded = false;

          const start = () => {
            if (loaded) return;
            loaded = true;
            if (loading) loading.textContent = 'Загрузка карты…';
            loadMap();
          };

          if (!('IntersectionObserver' in window)){
            start();
            return;
          }

          const obs = new IntersectionObserver((entries) => {
            for (const e of entries){
              if (e.isIntersecting){
                obs.disconnect();
                start();
                break;
              }
            }
          }, { root: null, rootMargin: SETTINGS.lazyRootMargin, threshold: 0.01 });

          obs.observe(mapRoot);
        }

        initLazy();
      </script>
    </body>
    </html>
    [/html]
    [hideprofile]

    0

    2

    [html]
    <script src="https://feather-tail.github.io/MyBB-scripts-bundle/js/theme-switcher/theme-iframe.js"></script>
    <script src="https://feather-tail.github.io/MyBB-scripts-bundle/js/font-resizer/font-resizer-iframe.js"></script>
    <style>
      :root { --frame-font-size: 14px; }

      html, body {
        font-size: var(--frame-font-size) !important;
      }

      .academy-section {
        margin: 18px 0 28px;
      }

      .academy-tabs {
        display: grid;
        gap: 14px;
        align-items: start;
        grid-template-columns: 1fr;
        background: var(--htm-clr);
        padding: 20px;
        border-radius: 5px;
        border: 1px solid var(--bord);
      }
      @media (min-width: 980px) {
        .academy-tabs {
          grid-template-columns: 320px 1fr;
        }
        .academy-tab-list {
          grid-column: 1;
        }
        .academy-tab-panels {
          grid-column: 2;
        }
      }

      .academy-tab-control {
        position: absolute;
        opacity: 0;
        pointer-events: none;
      }

      .academy-tab-list {
        display: grid;
        gap: 10px;
        text-align: left;
      }
      .academy-tab-list label {
        display: flex;
        align-items: center;
        gap: 10px;
        width: 100%;
        padding: 10px 14px;
        border: 1px solid var(--bord);
        border-radius: 5px;
        background: var(--quote);
        color: var(--sec-text, #0e0c0b);
        font-family: var(--main-font);
        cursor: pointer;
        text-transform: uppercase;
        letter-spacing: .3px;
        font-size: 13px;
        transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease,
          box-shadow 0.2s ease, transform 0.06s;
      }
      .academy-tab-list label:hover {
        background: rgba(201, 200, 200, 0.4);
      }
      .academy-tab-list label:active {
        transform: translateY(1px);
      }

      .academy-tabs
        > input:nth-of-type(1):checked
        ~ .academy-tab-list
        > label:nth-of-type(1),
      .academy-tabs
        > input:nth-of-type(2):checked
        ~ .academy-tab-list
        > label:nth-of-type(2),
      .academy-tabs
        > input:nth-of-type(3):checked
        ~ .academy-tab-list
        > label:nth-of-type(3),
      .academy-tabs
        > input:nth-of-type(4):checked
        ~ .academy-tab-list
        > label:nth-of-type(4),
      .academy-tabs
        > input:nth-of-type(5):checked
        ~ .academy-tab-list
        > label:nth-of-type(5),
      .academy-tabs
        > input:nth-of-type(6):checked
        ~ .academy-tab-list
        > label:nth-of-type(6),
      .academy-tabs
        > input:nth-of-type(7):checked
        ~ .academy-tab-list
        > label:nth-of-type(7),
      .academy-tabs
        > input:nth-of-type(8):checked
        ~ .academy-tab-list
        > label:nth-of-type(8),
      .academy-tabs
        > input:nth-of-type(9):checked
        ~ .academy-tab-list
        > label:nth-of-type(9) {
        background: var(--accent2);
        color: var(--bt-bg);
        border-color: var(--accent2);
      }

      .academy-tab-panels {
        border: 0;
        border-radius: 0;
        background: transparent;
        overflow: visible;
      }
      .academy-panel {
        display: none;
        border: 1px solid var(--bord);
        border-radius: 5px;
        background: var(--quote);
        overflow: hidden;
        font-family: var(--main-font);
      }

      .academy-tabs
        > input:nth-of-type(1):checked
        ~ .academy-tab-panels
        > .academy-panel:nth-of-type(1),
      .academy-tabs
        > input:nth-of-type(2):checked
        ~ .academy-tab-panels
        > .academy-panel:nth-of-type(2),
      .academy-tabs
        > input:nth-of-type(3):checked
        ~ .academy-tab-panels
        > .academy-panel:nth-of-type(3),
      .academy-tabs
        > input:nth-of-type(4):checked
        ~ .academy-tab-panels
        > .academy-panel:nth-of-type(4),
      .academy-tabs
        > input:nth-of-type(5):checked
        ~ .academy-tab-panels
        > .academy-panel:nth-of-type(5),
      .academy-tabs
        > input:nth-of-type(6):checked
        ~ .academy-tab-panels
        > .academy-panel:nth-of-type(6),
      .academy-tabs
        > input:nth-of-type(7):checked
        ~ .academy-tab-panels
        > .academy-panel:nth-of-type(7),
      .academy-tabs
        > input:nth-of-type(8):checked
        ~ .academy-tab-panels
        > .academy-panel:nth-of-type(8),
      .academy-tabs
        > input:nth-of-type(9):checked
        ~ .academy-tab-panels
        > .academy-panel:nth-of-type(9) {
        display: block;
      }

      .academy-panel-header {
        position: relative;
        overflow: hidden;
        background: var(--base-bg2) center/cover no-repeat;
      }
      .academy-panel-header img {
        display: block;
        width: 100%;
        height: auto;
        aspect-ratio: 16/7;
        object-fit: cover;
        filter: grayscale(1);
      }
      .academy-panel-header::after {
        content: '';
        position: absolute;
        inset: 0;
        background: linear-gradient(
          180deg,
          rgba(0, 0, 0, 0) 45%,
          rgba(0, 0, 0, 0.45) 100%
        );
      }
      .academy-panel-title {
        position: absolute;
        left: 16px;
        bottom: 10px;
        margin: 0;
        color: #fff;
        font-family: var(--sec-font, serif);
        text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
      }

      .academy-panel-body {
        padding: 12px 16px 16px;
        background: var(--htm-clr);
        margin: 20px;
        border-radius: 5px;
        font-size: 13px;
      }
      .academy-panel-body p {
        margin: 6px 0 10px;
        color: var(--text, #000);
        font-family: var(--main-font, system-ui, sans-serif);
      }

      .academy-panel-body details {
        margin: 14px 0 0;
        border: 1px solid var(--bord);
        border-radius: 5px;
        background: var(--quote);
        overflow: hidden;
      }
      .academy-panel-body summary {
        cursor: pointer;
        padding: 10px 14px;
        font-weight: 700;
        list-style: none;
        user-select: none;
      }
      .academy-panel-body summary::-webkit-details-marker {
        display: none;
      }
      .academy-panel-body summary::after {
        content: '+';
        float: right;
        font-weight: 700;
      }
      .academy-panel-body details[open] summary::after {
        content: '−';
      }
      .academy-panel-details-content {
        padding: 0 14px 12px;
      }
      .academy-panel-details-content p {
        margin: 8px 0;
      }

      @media (max-width: 640px) {
        .academy-panel-header img {
          aspect-ratio: 16/9;
        }
      }

      .academy-panel-body,
      .academy-tab-list label {
        font-size: inherit !important;
      }
    </style>

    <section id="main-building-interiors" class="academy-section">
      <div class="academy-tabs" role="tablist" aria-label="Помещения Главного корпуса">
        <input type="radio" name="tabs-main-interiors" id="tab-main-i-1" class="academy-tab-control" checked />
        <input type="radio" name="tabs-main-interiors" id="tab-main-i-2" class="academy-tab-control" />
        <input type="radio" name="tabs-main-interiors" id="tab-main-i-3" class="academy-tab-control" />
        <input type="radio" name="tabs-main-interiors" id="tab-main-i-4" class="academy-tab-control" />
        <input type="radio" name="tabs-main-interiors" id="tab-main-i-5" class="academy-tab-control" />
        <input type="radio" name="tabs-main-interiors" id="tab-main-i-6" class="academy-tab-control" />
        <input type="radio" name="tabs-main-interiors" id="tab-main-i-7" class="academy-tab-control" />
        <input type="radio" name="tabs-main-interiors" id="tab-main-i-8" class="academy-tab-control" />
        <input type="radio" name="tabs-main-interiors" id="tab-main-i-9" class="academy-tab-control" />

        <div class="academy-tab-list">
          <label for="tab-main-i-1"><span>Главный корпус</span></label>
          <label for="tab-main-i-2"><span>Административный блок</span></label>
          <label for="tab-main-i-3"><span>Столовая и кухня</span></label>
          <label for="tab-main-i-4"><span>Учебные аудитории</span></label>
          <label for="tab-main-i-5"><span>Помещение дисциплинарного комитета</span></label>
          <label for="tab-main-i-6"><span>Спортивный комплекс</span></label>
          <label for="tab-main-i-7"><span>Библиотека</span></label>
          <label for="tab-main-i-8"><span>Арена</span></label>
          <label for="tab-main-i-9"><span>Большой зал</span></label>
        </div>

        <div class="academy-tab-panels">
          <article class="academy-panel" role="tabpanel" aria-labelledby="tab-main-i-1">
            <header class="academy-panel-header">
              <div class="academy-panel-img">
                <div><img src="https://forumstatic.ru/files/001c/8d/fd/24675.png" alt="" /></div>
              </div>
              <h3 class="academy-panel-title">Главный корпус</h3>
            </header>
            <div class="academy-panel-body">
              <p>
                Главное здание Академии расположено в южной части острова, ближе к открытому побережью. Его архитектура сочетает массивные каменные конструкции и современные элементы: стекло, металл, строгие линии фасада. Здание выглядит устойчивым и замкнутым, словно изначально рассчитанным на суровые погодные условия и постоянное воздействие морского воздуха.
              </p>
              <p>
                Внутренние пространства организованы рационально: здесь расположены учебные аудитории, административные помещения, залы для собраний, спортивный зал с бассейном, кухня со столовой и множество комнат отдыха. Окна помещений выходят к морю, и шум волн нередко становится фоном для занятий и работы. Территория вокруг корпуса оформлена минималистично: каменные дорожки, открытые площадки и низкие ограды не отвлекают внимания от самого здания и окружающего пейзажа.
              </p>
            </div>
          </article>

          <article class="academy-panel" role="tabpanel" aria-labelledby="tab-main-i-2">
            <header class="academy-panel-header">
              <div class="academy-panel-img">
                <div><img src="https://forumstatic.ru/files/001c/8d/fd/24675.png" alt="" /></div>
              </div>
              <h3 class="academy-panel-title">Административный блок</h3>
            </header>
            <div class="academy-panel-body">
              <p>
                Административный блок располагается в башне восточного крыла Главного корпуса из которой открывается вид на весь остров. Внутри он представляет из себя светлые коридоры с современным дизайном.
              </p>
              <p>
                Здесь находятся канцелярия, кабинеты деканов и директора, архивы текущих дел, а также приёмная, в которой как и прежде на стене висит табличка «Тайна охраняет мир, знание — тех, кто в нём живёт.». В этом крыле всегда пахнет бумагой, кофе и морским ветром, который тянет с улицы, когда кто-то открывает окна.
              </p>
            </div>
          </article>

          <article class="academy-panel" role="tabpanel" aria-labelledby="tab-main-i-3">
            <header class="academy-panel-header">
              <div class="academy-panel-img">
                <div><img src="https://forumstatic.ru/files/001c/8d/fd/24675.png" alt="" /></div>
              </div>
              <h3 class="academy-panel-title">Столовая и кухня</h3>
            </header>
            <div class="academy-panel-body">
              <p>
                Столовая в Салеме находится на первом этаже Главного корпуса. Просторная и тёплая, с большими окнами, выходящими на гавань, она наполнена как небольшими, так и длинными столами для студентов, тянущимися через всё помещение. В дальнем конце столовой располагаются зоны, где могут уединиться преподаватели и сотрудники Академии, а вдоль большой стены напротив окон стоят островки с готовой едой на которых даже поздно вечером можно найти что-то простое и сытное.
              </p>
              <p>
                Кухня скрыта за отдельным проходом и работает как небольшая фабрика: с раннего утра и до позднего вечера повара трудятся, чтобы накормить всех студентов и сотрудников Академии.
              </p>
            </div>
          </article>

          <article class="academy-panel" role="tabpanel" aria-labelledby="tab-main-i-4">
            <header class="academy-panel-header">
              <div class="academy-panel-img">
                <div><img src="https://forumstatic.ru/files/001c/8d/fd/24675.png" alt="" /></div>
              </div>
              <h3 class="academy-panel-title">Учебные аудитории</h3>
            </header>
            <div class="academy-panel-body">
              <p>
                Учебные аудитории распределены по всем этажам Главного корпуса и представляют из себя как небольшие кабинеты, так и несколько крупных аудиторий, способных вместить в себя больше сотни студентов.
              </p>
              <p>
                По настроению аудитории очень разные и зависят от дисциплин и преподавателей, которые ведут в них занятия.
              </p>
            </div>
          </article>

          <article class="academy-panel" role="tabpanel" aria-labelledby="tab-main-i-5">
            <header class="academy-panel-header">
              <div class="academy-panel-img">
                <div><img src="https://forumstatic.ru/files/001c/8d/fd/24675.png" alt="" /></div>
              </div>
              <h3 class="academy-panel-title">Помещение дисциплинарного комитета</h3>
            </header>
            <div class="academy-panel-body">
              <p>
                Кабинет находится в Главном корпусе в дальнем углу на втором этаже западного крыла. Представляет из себя просторное светлое помещение в нейтральных тонах. В центре находится длинный стол, окружённый несколькими стульями, напротив на стене висит доска для заметок и записей на заседаниях, а по бокам расположены шкафчики для хранения личных дел и документов дисциплинарного комитета. В противоположном углу расположился буфет с неиссякаемым запасом чая, кофе и печенья на любой вкус и цвет, а на паре больших окон выстроились горшки неприхотливых домашних растений.
              </p>
            </div>
          </article>

          <article class="academy-panel" role="tabpanel" aria-labelledby="tab-main-i-6">
            <header class="academy-panel-header">
              <div class="academy-panel-img">
                <div><img src="https://forumstatic.ru/files/001c/8d/fd/24675.png" alt="" /></div>
              </div>
              <h3 class="academy-panel-title">Спортивный комплекс</h3>
            </header>
            <div class="academy-panel-body">
              <p>
                Спортивный комплекс Академии примыкает к западному крылу главного корпуса и занимает 1 и −1 этажи. Вход ведёт в светлый вестибюль с постом дежурного и стойками для инвентаря; дальше пространство расходится на несколько зон, чтобы занятия разных направлений не мешали друг другу.
              </p>
              <p>
                На 1 этаже расположены тренажёрные залы: кардио-секция с беговыми дорожками и дорожками для интервальных тренировок, силовой зал со свободными весами и станциями, а также функциональная зона для растяжки и работы с собственным весом. Там же находятся несколько рингов и площадка для спаррингов с мягким покрытием, настенными экранами для разбора техники и нишами для перчаток, бинтов и защиты. Здесь же находятся основные раздевалки: шкафчики, сушилки, душевые и отдельные кабины для быстрого восстановления (холодный душ/контраст).
              </p>
              <p>
                −1 этаж отдан под «мокрую» часть: бассейн с размеченными дорожками и небольшой зоной для отработки техники, зал реабилитации, кабинет спортивного врача, а также тихая комната для дыхательных практик и растяжки.
              </p>
              <p>
                Сердце комплекса — большое универсальное поле с искусственным газоном размером с футбольное. По периметру располагается внутренний круг для бега и разминки, а рядом — кладовые с мячами, щитами, конусами и переносными воротами. Обычно это поле используется для тренировок фамильяров, но частенько на нём можно увидеть студентов, играющих в какие-либо игры.
              </p>
            </div>
          </article>

          <article class="academy-panel" role="tabpanel" aria-labelledby="tab-main-i-7">
            <header class="academy-panel-header">
              <div class="academy-panel-img">
                <div><img src="https://forumstatic.ru/files/001c/8d/fd/24675.png" alt="" /></div>
              </div>
              <h3 class="academy-panel-title">Библиотека</h3>
            </header>
            <div class="academy-panel-body">
              <p>
                Библиотека в Салеме располагается в специальной пристройке соединённой с основной частью Главного зала в самой западной его части. Библиотека современная и светлая, и внутри имеется множество высоких книжных полок с передвижными лестницами, чтобы достать необходимое смог каждый даже с самых высоких полок. У входа располагается стойка библиотекаря, где студенты могут получить помощь, оформить выдачу книг или заказать новые.
              </p>
              <p>
                Учебная зона представляет собой множество столов, расставленных «островками» по несколько штук. За ними можно расположиться как в одиночестве, так и небольшой группой. На столах всегда есть канцелярские принадлежности для составления заметок. Часть столов оснащена компьютерами с доступом к открытым библиотечным онлайн-фондам мира.
              </p>
              <p>
                Фонд самой библиотеки включает учебную и художественную литературу, магические фолианты и древние манускрипты. Что-то удалось найти на руинах Фасги, другие — приобретены Академией или получены в дар из частных коллекций. Для быстрого поиска книги можно воспользоваться каталогом, помощью библиотекаря или небольшими зачарованными статуями кота — маскота салемской академии. Достаточно назвать название книги, и статуя подскажет нужный раздел и номер ряда. А если же студентов замучила жажда, то в разных концах помещения находится несколько кулеров с водой.
              </p>

              <details>
                <summary>Подробнее о фондах и зонах библиотеки</summary>
                <div class="academy-panel-details-content">
                  <p>
                    <strong>Зона открытого доступа:</strong><br>
                    · Учебный фонд: Учебники по теории Потока, базовые сборники заклинаний для начинающих, труды по истории магического сообщества, энциклопедии по магической флоре и фауне. Эти книги доступны всем студентам без специального разрешения. Они часто имеют защитные заклинания от выноса и порчи, но не несут в себе опасной информации.<br>
                    · Зона ведьм: Здесь можно найти углублённые труды по разным направлениям врождённого дара, сборники заклинаний по стихиям и техникам.<br>
                    · Зона фамильяров: Отделы с литературой по кинологии, орнитологии, герпетологии, но в магическом контексте. Книги об усилении звериной формы, техниках восприятия Потока и Скверны, травники и справочники по ингредиентам.
                  </p>

                  <p>
                    <strong>Зона Специальных Коллекций:</strong><br>
                    · Фолианты по уникальным дарам: Секции, посвящённые редким и малоизученным проявлениям магии. Доступ к ним получают студенты старших курсов с разрешения профильного декана.<br>
                    · Архив Инквизиции (копии): Копии документов, касающихся истории Инквизиции, протоколов допросов и описаний операций. Оригиналы хранятся в штаб-квартирах Инквизиции, но здесь собрана обширная база для изучения истории и тактики.<br>
                    · Картографическая комната: Огромная коллекция магических карт, многие из которых постоянно обновляются. Здесь можно найти карты потоков Потока, очагов Скверны, территорий Ковенов.<br>
                    · Зал Связи: Небольшая комната, где собраны труды, исследующие феномен Связи между ведьмой и фамильяром. Истории пар, теоретические выкладки, анализ сшивок. Это место пользуется особой популярностью у студентов, пытающихся понять свои отношения.
                  </p>

                  <p>
                    · Зал Запрещённых Книг: Здесь хранятся гримуары, содержащие опасные и тёмные заклинания, связанные со Скверной. Книги, которые «шепчут», пытаются влиять на читателя или сами по себе являются осквернёнными артефактами. Доступ сюда имеют только преподаватели и изредка — студенты выпускных курсов, выполняющие задания Дисциплинарной комиссии или декана полевых операций, и только в сопровождении опытного наставника-библиотекаря.<br>
                    · Редкие манускрипты: Древнейшие тексты, написанные до основания Инквизиции. Некоторые на неизвестных языках. Они хранятся в специальных магических капсулах, поддерживающих их сохранность. Изучать их можно только в самом Хранилище под наблюдением.
                  </p>

                  <p>
                    <strong>Зоны тишины и общения:</strong> в Главном зале — абсолютная тишина. В галереях можно перешёптываться, говорить вполголоса.
                  </p>

                  <p>
                    <strong>Выдача и возврат:</strong> книги из открытого доступа выдаются на руки под расписку, которая фиксирует, кто и когда взял книгу. Книги из Специальных коллекций и Крипты из библиотеки не выносятся.
                  </p>
                </div>
              </details>
            </div>
          </article>

          <article class="academy-panel" role="tabpanel" aria-labelledby="tab-main-i-8">
            <header class="academy-panel-header">
              <div class="academy-panel-img">
                <div><img src="https://forumstatic.ru/files/001c/8d/fd/24675.png" alt="" /></div>
              </div>
              <h3 class="academy-panel-title">Арена</h3>
            </header>
            <div class="academy-panel-body">
              <p>
                Подземная арена — место, где ведьмы и фамильяры могут использовать свои способности, не боясь рассекречивания и разрушения. Здесь проходят практические занятия и тренировки, а также спарринги и экзамены. При необходимости ведьмы и ведьмаки могут изменить ландшафт арены, создав полосу препятствий или особые климатические условия.
              </p>
              <p>
                Арена представляет собой большое открытое пространство в центре и трибуны вдоль одной из стен. Ничего лишнего здесь нет — даже отделки на стенах и уж тем более какого-то декора. Всё сделано так, чтобы в случае разбушевавшейся магии не пришлось каждый раз переделывать и чинить.
              </p>
              <p>
                Защита повсюду в основном магическая, чтобы способности не могли нанести вред и вырваться куда-то за пределы арены. Во время каких-либо событий трибуну укрывают барьером.
              </p>
            </div>
          </article>

          <article class="academy-panel" role="tabpanel" aria-labelledby="tab-main-i-9">
            <header class="academy-panel-header">
              <div class="academy-panel-img">
                <div><img src="https://forumstatic.ru/files/001c/8d/fd/24675.png" alt="" /></div>
              </div>
              <h3 class="academy-panel-title">Большой зал</h3>
            </header>
            <div class="academy-panel-body">
              <p>
                Большой зал расположен в Главном корпусе и служит пространством, где учебная жизнь легко перетекает в общественную.
              </p>
              <p>
                Это просторное помещение с высоким потолком, длинными окнами и сценой в глубине. В обычные дни здесь могут проходить крупные лекции, семинары и собрания, а по вечерам зал меняется: на сцене ставят спектакли, показывают фильмы, выступают кружки и музыкальные группы, а в праздники пространство заполняют огни, украшения и музыка.
              </p>
              <p>
                Интерьер сочетает академическую строгость и уют. Светлое дерево, тёмный камень, мягкое освещение, плотные шторы и хорошая акустика делают зал одинаково подходящим и для официальных мероприятий, и для чего-то более тёплого, студенческого. Стулья и часть оборудования можно быстро убрать, освобождая место для ярмарок, балов, дискотек или праздничных вечеров.
              </p>
              <p>
                У студентов Большой зал давно считается местом, где Академия особенно ясно ощущается не только как учебное заведение, но и как маленький отдельный мир, в котором все рано или поздно оказываются рядом.
              </p>
            </div>
          </article>
        </div>
      </div>
    </section>
    [/html]
    [hideprofile]

    0


    Вы здесь » Kindred Spirits » Информация о мире » Локации Академии


    Рейтинг форумов | Создать форум бесплатно