мистика — расы — вуду — nc-18
новый орлеан — осень 2025
«Но я тут пока ничего ещё не сделала, и надеюсь, конечно, не придется. Хотелось бы заработать легких денежек и свалить на пляж в Канкун. Делить теплый песок с игуанами и запивать всё это дело тазиком маргариты. Зависнуть на месяц, пока от отдыха не начнет тошнить, а потом... Может, снова работать. И повторить всё по кругу ещё несколько раз, пока не случится что-то, что изменит мою жизнь настолько, что я добровольно захочу вернуться домой».

наш телеграм канал

Unholy Mess

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

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


Вы здесь » Unholy Mess » Veritas occultatur in tenebris » Сюжет


Сюжет

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

1

Unholy Mess

https://i.imgur.com/Ffc8mFk.gif https://i.imgur.com/pgwnOdd.gif

мистика

расы

вуду

  ✥

nc-21

[indent] Магия всегда жила в тени. Она скользила по узким улочкам и пряталась в переливах болотного тумана, прорывалась сквозь шепот костяных бусин в лавках старых колдуний и дымилась в чашах с травами, подмешанными в ром. Люди любили мистику, но не верили в нее по-настоящему — и это спасало их. Они могли слышать истории о том, как французский квартал населен духами, а в закоулках Мариньи нельзя свистеть по ночам. Но они не знали, что за этими легендами стояла реальность, управляемая тайными законами.
[indent] Век назад ковен Собо наложил на город свое заклятие — изящное, как кружевной веер, и крепкое, как цепи для буйных. Оно сковало магические создания, подчинило их воле ведьм и не позволило вырваться из-под власти тайных законов. Источник силы, скрытый в самом сердце города, питал это заклинание, не давая монстрам вновь стать монстрами. Более столетия все магические существа Нового Орлеана пребывали под контролем заклинания, не позволявшего в полную мощь использовать собственную силу, вместо этого служить ковену и под страхом смерти бояться нарушить жесточайшие правила. Вампирам было запрещено питаться непосредственно живым человеком, оборотни и суккубы не могли связывать свою жизнь с людьми, а у ведьм действовало вето на практику вуду. Всё это поддерживало хрупкий баланс и защищало Новый Орлеан от внимания Стражей, что следят за соблюдением интересов обычных людей, наименее защищённого звена в иерархии созданий.
[indent] И всё шло относительно мирно, пока ураган Катрина не взял и не провернул трюк, который не удалось ни одному мятежнику за век. Ураган треснул сам источник силы, словно старый глиняный кувшин, и его обломки разлетелись по городу. Магические кланы бросились их расхватывать, мечтая наконец-то избавиться от власти Собо. И всё же правила устояли, пока в конце 2024 года сборные силы повстанцев не разорвали заклятие в клочья. Крупнейшая магическая битва привела к падению ковена Собо, а значит, более правила не действовали, и началось разделение власти среди тех, кого она волновала. Остальные существа ощутили вкус свободы и во всю принялись ею пользоваться. Ранее бежавшие из города создания возвращаются, Новый Орлеан привлекает и новых гостей, которые были изгнаны из своих родных мест. Количество столкновений и жертв возрастала, и Беззаботный город переставал быть таковым на глазах. Новый Орлеан — город, где духи всегда были шумными соседями, — стал по-настоящему громким местом.
[indent] Классические одиночки вампиры устраивают кровавые пиршества, оборотни вновь объединяются в стаи, суккубы наслаждаются [censure], а ведьмы и ведьмаки возрождают вуду и формируют новые кланы. Очаги возгорания из мелких и крупных битв призывают на землю всё больше валькирий и работы по сопровождению павших в бою на тот свет мало у них не будет. Стражи в экстренном порядке отправляют своих представителей в Новый Орлеан, но здесь теперь царит Хаос, и вопрос уже не в том, удастся ли им восстановить порядок, а в том, сколько жертв поляжет во славу воцарившейся анархии.

+1

2

Corpus Juris

❖ Правила ❖ действовали для всех магических существ в Новом Орлеане более ста лет до 2025-го года. 

Правила — мощное заклинание, которое на физическом уровне не позволяло существам на территории Нового Орлена нарушать установленный ковеном Собо порядок вещей. Попытка нарушить вызывала сильнейшую боль, но, если и ей удавалось противостоять, то после нарушитель погибал.

Ковен Собо не был чистым злом – они действовали в стиле "мы контролируем вас, но зато вас не сожгут". Они монополизировали власть, но в обмен давали защиту, рынок и относительно мирное существование. Их свержение дало магическим существам свободу, но теперь город накрыла настоящая анархия.

Отрицательные правила (ущемляющие природу существ)

[indent] Вампиры – диета без живой крови
Живых людей кусать запрещено! Только бутилированная или добровольная кровь из банков.
❖ Проблема: Гурманы рыдают. Молодые вампиры злятся. Охотники за адреналином скучают.
[indent] Оборотни – никакой межвидовой романтики
Никаких браков и связей с людьми!
❖ Проблема: Любовь – штука капризная. Чем строже запрет, тем больше искушение. Ромео и Джульетты с хвостами периодически объявляются.
[indent] Суккубы – ограничение по жертвам
Энергетическое кормление только от существ. И никаких несогласных!
❖ Проблема: Суккубы стали избирательнее, а люди… менее удовлетворены.
[indent] Ведьмы – запрет на вуду
Никаких проклятий, духов предков, зомби и договоров с Лоа. Все заклинания только в рамках "безопасной" магии!
❖ Проблема: Ограничение знаний делает многих ведьм слабее. Те, кто раньше вели переговоры с духами, теперь варят травяные чаи.
[indent] Общий запрет на "хаотичное насилие"
Драться можно только в специально отведённых местах и в пределах разумного (например, не на глазах у людей и не с применением магии массового поражения).
❖ Проблема: Наёмные убийцы и агрессивные личности разоряются. Вампиры и оборотни периодически устраивают подпольные бои.
[indent] Без спонтанных превращений! (для оборотней)
Превращаться в волков (или другие формы) можно только в специально отведённых местах или при крайней необходимости. И никаких бегов по улицам в полнолуние!
❖ Проблема: Инстинкты штука сложная, особенно под полной луной. А ещё обидно, когда чувствуешь опасность, а обернуться нельзя.
[indent] Никакой некромантии в черте города! (для ведьм)
Призрак в доме – это романтично, но толпы мертвецов на улицах – нет. Воскрешение, подчинение духов и зомби-слуги под запретом!
❖ Проблема: Любители общаться с духами предков негодуют. А кое-кто из ведьм теряет свой главный козырь в борьбе за власть.
[indent] Без ментального контроля! (для суккубов, вампиров и ведьм)
Гипноз, очарование, насильственное подчинение воли – всё запрещено без добровольного согласия.
❖ Проблема: Это рушит классические схемы соблазнения у суккубов. Теперь приходится реально стараться!
[indent] Никаких стихийных катастроф в рамках города!
Магические создания не имеют права вызывать ураганы, наводнения, землетрясения и другие природные катаклизмы в черте Нового Орлеана.
❖ Проблема: Любители "случайных" бурь и молний в неблагонадёжных районах вынуждены изощряться.
[indent] Вампирские обращённые – только по лицензии!
Хотите сделать нового вампира? Подайте заявку в ковен, получите разрешение и приведите его на ритуал. Спонтанные обращения – вне закона.
❖ Проблема: Старые вампиры держат монополию, а новичкам приходится ждать одобрения.

Положительные правила (выгодные для существ и ковена)

[indent] Общий бизнес "Ночной Орлеан"
Ковен управляет теневыми и легальными сферами города: ночными клубами, отелями, казино и заведениями с экзотическими услугами. Все существа могут работать и получать свою долю.
❖ Плюсы: Доход стабилен, есть безопасные места для кормления, общения и магической практики.
[indent] Легальные арены для дуэлей
Хочешь решить спор? Есть лицензированные арены, где можно выпустить пар без риска полного уничтожения (ну, почти).
❖ Плюсы: Честные схватки, ставки, зрелище. Вампиры, оборотни и ведьмы могут устраивать бои по правилам.
[indent] Банки крови и энергия на продажу
Вампиры могут покупать качественную кровь, а суккубы – энергию, полученную с разрешения людей. Это как спа, но для нечисти.
❖ Плюсы: Контроль качества, безопасность, стабильные поставки.
[indent] Магический рынок
Разрешено торговать артефактами, зельями, заклинаниями – но только через официальные каналы ковена, с налогами и лицензиями.
❖ Плюсы: Гарантия качества, защита покупателей, богатый ассортимент.
[indent] Пакт со Стражами
Если строго соблюдать правила, Стражи не вмешиваются. Ковен обеспечивал баланс, чтобы не прилетели охотники на монстров с факелами.
❖ Плюсы: Город не разносили в щепки, магические существа могли жить относительно спокойно.
[indent] Зона нейтралитета
Французский квартал объявлен территорией без конфликтов. Здесь нельзя убивать, калечить или открыто демонстрировать магию. Нарушитель будет наказан.
❖ Плюсы: Безопасное место для встреч, сделок, отдыха.
[indent] Официальные медиаторы
Если у магических существ есть спор, его можно решить не в кровавой бойне, а через арбитров ковена. Они решают, кто прав, кто виноват, и какие санкции применить.
❖ Плюсы: Честные (ну, относительно) разбирательства, меньше смертей по глупости.
[indent] Программа защиты существ
Если кого-то преследуют Стражи или охотники, можно запросить убежище у ковена. При определённых условиях, конечно…
❖ Плюсы: Безопасность, шанс на новую жизнь.
[indent] Магическое страхование
Платишь определённый процент дохода – получаешь защиту. Если тебя кто-то убивает, ковен накажет обидчика (если это не самоубийство, конечно).
❖ Плюсы: Кому-то это давало гарантии, а кто-то просто спонсировал ковен ради спокойствия.
[indent] Лига развлечений
Ковен спонсировал магические спектакли, бои, турниры и прочие шоу для существ. Это помогало выпускать пар без разрушений.
❖ Плюсы: Возможность легально соревноваться, показывать свою силу и талант.

+2

3

[html]<!doctype html>
<html lang="ru">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Календарь</title>
  <style>
    :root{
      --bg: #0b1020;
      --text: #000000;
      --ring: 0 0 0 2px rgba(236,127,73,.45), 0 0 30px rgba(236,127,73,.15); /* #c4534b glow */
      --radius: 16px;
    }

    html,body{
      height:100%;
      margin:0;
      font: 16px/1.5 'El Messiri' !important;
      color: var(--text);
      background: radial-gradient(1200px 800px at 10% 0%, #101a33 0%, var(--bg) 60%);
      display:flex; align-items:center; justify-content:center; padding:24px;
    }

    .wrap{width:min(1100px, 95vw);}
    h1{font-size:clamp(22px, 3vw, 28px); margin:0 0 14px; font-weight:700; letter-spacing:.2px;}
    .sub{color:#000000; margin:0 0 18px;}

    .calendar{
      position: relative;
      background: transparent; /* фон календаря прозрачный */
      border: 1px solid rgba(0,0,0,.06);
      border-radius: var(--radius);
      box-shadow: 0 10px 40px rgba(0,0,0,.08), inset 0 0 0 1px rgba(0,0,0,.04);
      overflow: hidden;
    }

    .months{ display:flex; gap:2px; }
    .month{
      flex:1; min-width: 460px;
      background: transparent; /* прозрачный фон месяца */
      border-radius: calc(var(--radius) - 2px);
      padding: 12px 12px 16px;
      border: 1px solid rgba(0,0,0,.06);
    }
    .month h2{ margin: 4px 6px 10px; font-family: 'Playfair Display SC' !important;
    font-size: 30px;
    font-style: italic;
    text-shadow: 0 0 5px #6c5443; }

    table{ width:100%; border-collapse: collapse; table-layout: fixed;}
    thead th{
      font-size:12px; color: #000000; font-weight:600; text-transform: uppercase; letter-spacing:.08em; padding:8px 4px 10px; border-bottom:1px solid rgba(0,0,0,.06);
    }
    td{
      vertical-align: top; height: 92px; padding:8px;
      border: 1px solid rgba(0,0,0,.06); /* как у .month */
      position: relative; background: rgba(171,152,145,.50); /* a49a98 @ 50% */
    }
    td.is-out{ opacity: .35; }

    .day-number{ font-size: 12px; color:#000000; font-weight:600; }

    .event{
      margin-top:6px; display:inline-flex; align-items:center; gap:6px; padding:6px 8px; border-radius:10px;
      background: rgba(241,84,6,.12);
      border: 1px dashed rgba(241,84,6,.40);
      color:#000000; cursor: pointer;
      user-select:none; outline: none; white-space: nowrap; max-width: 100%; overflow:hidden; text-overflow: ellipsis;
      transition: box-shadow .2s ease, transform .2s ease;
    }
    .event:hover{ box-shadow: var(--ring); }
    .event:focus-visible{ outline: none; box-shadow: var(--ring); }
    .event .dot{ width:8px; height:8px; border-radius:50%; background: #515966; flex:0 0 8px; }

    /* === Панель подробностей по принципу «мироописание от духа» === */
    .info-panel{
      position:absolute; z-index:5;
      /* Центр по ширине без translate — строгие поля дают 80% ширины */
      left:10%; right:10%; width:auto; /* 80% ширины контейнера */
      /* Высота не более 50% контейнера */
      max-height:50%; top:25px;

      background:#ab9891; color:#111;
      box-shadow: 0 0 0 5px #ab9891 inset, 0 0 0 10px rgba(0,0,0,.1) inset;
      border-radius: 14px; padding:25px; text-align:left;
      overflow:hidden;
      /* Анимация появления/сворачивания */
      opacity:0; transform: translateY(-8px) scale(.98); transition: opacity .22s ease, transform .24s ease;
      visibility: hidden; pointer-events:none;
    }
    .info-panel.is-open{ opacity:1; transform: translateY(0) scale(1); visibility: visible; pointer-events:auto; }
    .info-panel > .info-panel__content{ overflow-y:auto; height: calc(100% - 35px); padding-right:5px; }
    .info-panel h5{ font: 700 20px 'El Messiri', sans-serif; margin:20px 0 10px; position:relative; padding-left:45px; }
    .info-panel h5:before{ content:""; height:2px; width:30px; background: rgba(0,0,0,.7); position:absolute; left:0; top:50%; transform: translateY(-50%); }
    .info-panel em{ font: 400 italic 11px 'El Messiri', sans-serif; display:block; border-right:5px solid rgba(0,0,0,.1); padding-right:10px; text-align:right; margin:10px 0; }
    .close-btn{ background: rgba(0,0,0,.04); border:1px solid rgba(0,0,0,.06); height:15px; text-transform:uppercase; font: 600 10px/15px 'El Messiri', sans-serif; text-align:center; margin-bottom:20px; cursor:pointer; letter-spacing:2px; }

    /* Адаптив */
    @media (max-width: 980px){
      .months{ flex-direction: column; }
      .month{ min-width: unset; }
      td{ height: 80px; }
      /* На мобилках делаем шире и чуть выше */
      .info-panel{ left:4%; right:4%; max-height:60%; top:12px; padding:18px; }
    }
  </style>
</head>
<body>
  <div class="wrap">
 
    <div class="calendar" id="calendar">
      <div class="months">
        <!-- Сентябрь 2025 -->
        <section class="month" aria-label="Сентябрь 2025">
          <h2>2025, Sept</h2>
          <table role="grid" aria-labelledby="m-sep">
            <thead>
              <tr><th>Пн</th><th>Вт</th><th>Ср</th><th>Чт</th><th>Пт</th><th>Сб</th><th>Вс</th></tr>
            </thead>
            <tbody>
              <tr>
                <td><span class="day-number">1</span>
      <button class="event" data-title="ООО КровьДляВсех" data-when="01 сентября, 12:00" data-where="последний дом на Бурбон-стрит" data-text="Как дети в школу, вампиры решили пойти подкрепиться. Но немного переборщили с масштабами. В подвале последнего дома на Бурбон-стрит начала работу фабрика по извлечению крови из живых (и очень сопротивляющихся) людей." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span> ООО КровьДляВсех
                  </button></td>
                <td><span class="day-number">2</span></td>
                <td><span class="day-number">3</span></td>
                <td><span class="day-number">4</span></td>
                <td><span class="day-number">5</span></td>
                <td><span class="day-number">6</span></td>
                <td><span class="day-number">7</span></td>
              </tr>
              <tr>
                <td><span class="day-number">8</span></td>
                <td><span class="day-number">9</span></td>
                <td><span class="day-number">10</span>
      <button class="event" data-title="Censured" data-when="10 сентября, 21:00" data-where="район Ривер Ридж" data-text="Обнаружение старинного артефакта усиливает способности пары суккубов, что проводит к аномальной вспышке сексуального желания у окружающих." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span> Censured
                  </button></td>
                <td><span class="day-number">11</span></td>
                <td><span class="day-number">12</span></td>
                <td><span class="day-number">13</span></td>
                <td><span class="day-number">14</span></td>
              </tr>
              <tr>
                <td><span class="day-number">15</span></td>
                <td><span class="day-number">16</span>
      <button class="event" data-title="Съезд СМС" data-when="16 сентября, 10:00-18:00" data-where="отель Four Seasons, Канал-Стрит 2" data-text="Обмен опытом, наработками и общение стражей со всего мира происходит в Новом Орлеане. Несомненно у организации хватает недоброжелателей, чтобы испортить им мероприятие. Когда в отеле раздаётся первый взрыв, даже обычные люди начинают догадываться, что дело вовсе не в утечке газа." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span> Съезд СМС
                  </button></td>
                <td><span class="day-number">17</span></td>
                <td><span class="day-number">18</span></td>
                <td><span class="day-number">19</span></td>
                <td><span class="day-number">20</span>
                  <button class="event" data-title="Турнир по волейболу: вампиры против оборотней" data-when="20 сентября, 22:00–04:00" data-where="Сангрилла Секретный пляж" data-text="Командный турнир 6×6. Стоило Новому Орлеану освободиться от власти ковена Собо, магические представители города отказались от всего былого... кроме любимого события: шестёрка лучших оборотней встречается с шестью наиболее способными вампирами, чтобы в жестоком бою доказать, кто из них лучший - в волейболе. Настоящий песок у бассейна элитного комплекса и искусственное солнце, что не вредит упырям. Получить приглашение на это мероприятие - уже честь. Здесь лучшие угощения, а шоу в перерывах не уступает Half-Time Супер Боула. Здесь налаживают контакты и просто хорошо проводят время. Будет ли и в этот раз так радужно или кому-то турнир всё-таки не угодил?" aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span> Турнир по волейболу
                  </button>
                </td>
                <td><span class="day-number">21</span></td>
              </tr>
              <tr>
                <td><span class="day-number">22</span></td>
                <td><span class="day-number">23</span></td>
                <td><span class="day-number">24</span></td>
                <td><span class="day-number">25</span>
      <button class="event" data-title="Крик баньши" data-when="25 - 27 сентября" data-where="Новый Орлеан" data-text="Возросшее количество смертей и затяжная пасмурная погода повысили концентрацию баньши в городе. Покоя от их крика нет ни простым смертным, ни магическим существам." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span> Крик баньши
                  </button></td>
                <td><span class="day-number">26</span>
      <button class="event" data-title="Крик баньши" data-when="25 - 27 сентября" data-where="Новый Орлеан" data-text="Возросшее количество смертей и затяжная пасмурная погода повысили концентрацию баньши в городе. Покоя от их крика нет ни простым смертным, ни магическим существам." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span>
                  </button></td>
                <td><span class="day-number">27</span>
      <button class="event" data-title="Крик баньши" data-when="25 - 27 сентября" data-where="Новый Орлеан" data-text="Возросшее количество смертей и затяжная пасмурная погода повысили концентрацию баньши в городе. Покоя от их крика нет ни простым смертным, ни магическим существам." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span>
                  </button></td>
                <td><span class="day-number">28</span></td>
              </tr>
              <tr>
                <td><span class="day-number">29</span></td>
                <td><span class="day-number">30</span>
      <button class="event" data-title="Восстание мертвецов" data-when="30 сентября, 00:00–06:00" data-where="кладбище Сент-Луи" data-text="После снятия запрета на некроматию ведьмы города зачастили на кладбище Сент-Луи. Заигрывание с мистическими силами идёт не по плану, когда один за другим воскресают духи каждого, кто был захоронен здесь. И, если этого недостаточно, за духами выбираются их разной степени разложившиеся тела. Пока призраки завершают свои земные дела и проведывают родственников, на кладбище разворачивается через чур реалистичный эпизод сериала Walking Dead." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span> Восстание мертвецов
                  </button></td>
                <td class="is-out"></td>
                <td class="is-out"></td>
                <td class="is-out"></td>
                <td class="is-out"></td>
                <td class="is-out"></td>
              </tr>
            </tbody>
          </table>
        </section>
      </div>

      <!-- мироописание от духа -->
      <div class="info-panel" id="infoPanel" aria-live="polite" aria-atomic="true" role="dialog" aria-modal="false">
        <div class="close-btn" id="panelClose">— закрыть —</div>
        <div class="info-panel__content">
          <h5 id="panelTitle">Заголовок</h5>
          <em id="panelMeta">Когда и где</em>
          <div id="panelBody">Текст</div>
        </div>
      </div>
    </div>
  </div>

  <script>
    (function(){
      // === ЭЛЕМЕНТЫ ===
      const calendar = document.getElementById('calendar');
      const panel = document.getElementById('infoPanel');
      const panelClose = document.getElementById('panelClose');
      const pTitle = document.getElementById('panelTitle');
      const pMeta = document.getElementById('panelMeta');
      const pBody = document.getElementById('panelBody');

      let currentTrigger = null;

      // === ОТКРЫТИЕ ПАНЕЛИ ===
      function openFromTrigger(btn){
        currentTrigger = btn;
        pTitle.textContent = btn.dataset.title || btn.textContent.trim();
        const whenTxt = btn.dataset.when ? btn.dataset.when : '';
        const whereTxt = btn.dataset.where ? (whenTxt ? ' · ' : '') + btn.dataset.where : '';
        pMeta.textContent = (whenTxt + whereTxt).trim();
        pBody.textContent = btn.dataset.text || '';
        panel.classList.add('is-open');
        panel.setAttribute('aria-modal','true');
        panelClose.focus();
      }

      // === ЗАКРЫТИЕ ПАНЕЛИ ===
      function closePopover(){
        panel.classList.remove('is-open');
        panel.setAttribute('aria-modal','false');
        if (currentTrigger) currentTrigger.focus();
      }

      // === СЛУШАТЕЛИ ===
      calendar.addEventListener('click', (e)=>{
        const btn = e.target.closest('.event');
        if (!btn) return;
        openFromTrigger(btn);
      });

      panelClose.addEventListener('click', closePopover);
      document.addEventListener('keydown', (e)=>{ if (e.key === 'Escape') closePopover(); });

      // Быстрое копирование по двойному клику по заголовку
      pTitle.addEventListener('dblclick', async ()=>{
        const text = `${pTitle.textContent}\n${pMeta.textContent}\n\n${pBody.textContent}`.trim();
        try { await navigator.clipboard.writeText(text); } catch(e){}
      });

      // === Самопроверка/"тесты" в консоли ===
      (function selfTest(){
        const results = [];
        const reqIds = ['calendar','infoPanel','panelClose','panelTitle','panelMeta','panelBody'];
        const missing = reqIds.filter(id => !document.getElementById(id));
        results.push(['IDs exist', missing.length===0, missing.length ? ('missing: '+missing.join(', ')) : 'ok']);
        const eventsCount = document.querySelectorAll('.event').length;
        results.push(['Events present', eventsCount>0, 'count='+eventsCount]);
        console.groupCollapsed('%cCalendar self-test','background:#0f1630;color:#cfe0ff;padding:2px 6px;border-radius:6px');
        results.forEach(([name, ok, msg])=> console[ok?'log':'warn'](`${name}: ${ok?'OK':'FAIL'} (${msg})`));
        console.groupEnd();
        if (location.hash === '#test' && eventsCount){
          const first = document.querySelector('.event');
          openFromTrigger(first);
          setTimeout(closePopover, 1200);
        }
      })();
    })();
  </script>
</body>
</html>
[/html]
[html]<!doctype html>
<html lang="ru">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Календарь</title>
  <style>
    :root{
      --bg: #0b1020;
      --text: #000000;
      --ring: 0 0 0 2px rgba(236,127,73,.45), 0 0 30px rgba(236,127,73,.15); /* #c4534b glow */
      --radius: 16px;
    }

    html,body{
      height:100%;
      margin:0;
      font: 16px/1.5 'El Messiri' !important;
      color: var(--text);
      background: radial-gradient(1200px 800px at 10% 0%, #101a33 0%, var(--bg) 60%);
      display:flex; align-items:center; justify-content:center; padding:24px;
    }

    .wrap{width:min(1100px, 95vw);}
    h1{font-size:clamp(22px, 3vw, 28px); margin:0 0 14px; font-weight:700; letter-spacing:.2px;}
    .sub{color:#000000; margin:0 0 18px;}

    .calendar{
      position: relative;
      background: transparent; /* фон календаря прозрачный */
      border: 1px solid rgba(0,0,0,.06);
      border-radius: var(--radius);
      box-shadow: 0 10px 40px rgba(0,0,0,.08), inset 0 0 0 1px rgba(0,0,0,.04);
      overflow: hidden;
    }

    .months{ display:flex; gap:2px; }
    .month{
      flex:1; min-width: 460px;
      background: transparent; /* прозрачный фон месяца */
      border-radius: calc(var(--radius) - 2px);
      padding: 12px 12px 16px;
      border: 1px solid rgba(0,0,0,.06);
    }
    .month h2{ margin: 4px 6px 10px; font-family: 'Playfair Display SC' !important;
    font-size: 30px;
    font-style: italic;
    text-shadow: 0 0 5px #6c5443; }

    table{ width:100%; border-collapse: collapse; table-layout: fixed;}
    thead th{
      font-size:12px; color: #000000; font-weight:600; text-transform: uppercase; letter-spacing:.08em; padding:8px 4px 10px; border-bottom:1px solid rgba(0,0,0,.06);
    }
    td{
      vertical-align: top; height: 92px; padding:8px;
      border: 1px solid rgba(0,0,0,.06); /* как у .month */
      position: relative; background: rgba(171,152,145,.50); /* a49a98 @ 50% */
    }
    td.is-out{ opacity: .35; }

    .day-number{ font-size: 12px; color:#000000; font-weight:600; }

    .event{
      margin-top:6px; display:inline-flex; align-items:center; gap:6px; padding:6px 8px; border-radius:10px;
      background: rgba(241,84,6,.12); /* 993933 с прежней прозрачностью */
      border: 1px dashed rgba(241,84,6,.40);
      color:#000000; cursor: pointer;
      user-select:none; outline: none; white-space: nowrap; max-width: 100%; overflow:hidden; text-overflow: ellipsis;
      transition: box-shadow .2s ease, transform .2s ease;
    }
    .event:hover{ box-shadow: var(--ring); }
    .event:focus-visible{ outline: none; box-shadow: var(--ring); }
    .event .dot{ width:8px; height:8px; border-radius:50%; background: #515966; flex:0 0 8px; }

   /* === Панель подробностей по принципу «мироописание от духа» === */
    .info-panel{
      position:absolute; z-index:5;
      /* Центр по ширине без translate — строгие поля дают 80% ширины */
      left:10%; right:10%; width:auto; /* 80% ширины контейнера */
      /* Высота не более 50% контейнера */
      max-height:50%; top:25px;

      background:#ab9891; color:#111;
      box-shadow: 0 0 0 5px #ab9891 inset, 0 0 0 10px rgba(0,0,0,.1) inset;
      border-radius: 14px; padding:25px; text-align:left;
      overflow:hidden;
      /* Анимация появления/сворачивания */
      opacity:0; transform: translateY(-8px) scale(.98); transition: opacity .22s ease, transform .24s ease;
      visibility: hidden; pointer-events:none;
    }
    .info-panel.is-open{ opacity:1; transform: translateY(0) scale(1); visibility: visible; pointer-events:auto; }
    .info-panel > .info-panel__content{ overflow-y:auto; height: calc(100% - 35px); padding-right:5px; }
    .info-panel h5{ font: 700 20px 'El Messiri', sans-serif; margin:20px 0 10px; position:relative; padding-left:45px; }
    .info-panel h5:before{ content:""; height:2px; width:30px; background: rgba(0,0,0,.7); position:absolute; left:0; top:50%; transform: translateY(-50%); }
    .info-panel em{ font: 400 italic 11px 'El Messiri', sans-serif; display:block; border-right:5px solid rgba(0,0,0,.1); padding-right:10px; text-align:right; margin:10px 0; }
    .close-btn{ background: rgba(0,0,0,.04); border:1px solid rgba(0,0,0,.06); height:15px; text-transform:uppercase; font: 600 10px/15px 'El Messiri', sans-serif; text-align:center; margin-bottom:20px; cursor:pointer; letter-spacing:2px; }

    /* Адаптив */
    @media (max-width: 980px){
      .months{ flex-direction: column; }
      .month{ min-width: unset; }
      td{ height: 80px; }
      /* На мобилках делаем шире и чуть выше */
      .info-panel{ left:4%; right:4%; max-height:60%; top:12px; padding:18px; }
    }
  </style>
</head>
<body>
  <div class="wrap">
 
    <div class="calendar" id="calendar">
      <div class="months">
              <!-- Октябрь 2025 -->
        <section class="month" aria-label="Октябрь 2025">
          <h2>2025, Oct</h2>
          <table role="grid">
            <thead>
              <tr><th>Пн</th><th>Вт</th><th>Ср</th><th>Чт</th><th>Пт</th><th>Сб</th><th>Вс</th></tr>
            </thead>
            <tbody>
              <tr>
                <td class="is-out"></td>
                <td class="is-out"></td>
                <td><span class="day-number">1</span></td>
                <td><span class="day-number">2</span></td>
                <td><span class="day-number">3</span></td>
                <td><span class="day-number">4</span>
      <button class="event" data-title="Задержка рейсов" data-when="04 октября, 09:00–23:00" data-where="аэропорт им. Луи Армстронга" data-text="Колдун, опаздывающий на свой самолёт, - горе в семье. А ещё - в целом городе. Сверхплотный туман заволакивает городской аэропорт, создавая транспортный коллапс. НЕестественное явление не позволяет покинуть здание, а стоит туману пробраться внутрь, как становится ясно, что монстры скрываются не только во тьме, но и в мельчайших частицах воды, которые скопились в воздухе." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span> Задержка рейсов
                  </button></td>
                <td><span class="day-number">5</span></td>
              </tr>
              <tr>
                <td><span class="day-number">6</span></td>
                <td><span class="day-number">7</span>
      <button class="event" data-title="La Maison de papier" data-when="07 октября, 13:00–19:00" data-where="магический рынок" data-text="Ещё один вторник на магическом рынке (скрытые от туристов ряды с волшебными товарами, а также отдельные магазины) становится совсем не скучным. Банда грабителей в результате неудачного стечения обстоятельств берёт в заложники персонал и посетителей самого дорого магазина. Успеют ли СМС вмещаться до того, как прольётся первая кровь? (Нет)." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span> La Maison de papier
                  </button></td>
                <td><span class="day-number">8</span></td>
                <td><span class="day-number">9</span></td>
                <td><span class="day-number">10</span></td>
                <td><span class="day-number">11</span></td>
                <td><span class="day-number">12</span></td>
              </tr>
              <tr>
                <td><span class="day-number">13</span></td>
                <td><span class="day-number">14</span></td>
                <td><span class="day-number">15</span></td>
                <td><span class="day-number">16</span>
                  <button class="event" data-title="Неделя террора" data-when="16 - 23 октября" data-where="болота Манчак" data-text="День, когда на болотах было обнаружено первое растерзанное тело. Ругару терроризует болота в течении недели. Кемпинг и туристические экскурсии следовало бы отложить, но остались смельчаки, что не склонны менять планы." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span> Неделя террора
                  </button>
                </td>
                <td><span class="day-number">17</span>
                  <button class="event" data-title="Неделя террора" data-when="16 - 23 октября" data-where="болота Манчак" data-text="День, когда на болотах было обнаружено первое растерзанное тело. Ругару терроризует болота в течении недели. Кемпинг и туристические экскурсии следовало бы отложить, но остались смельчаки, что не склонны менять планы." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span>
                  </button></td>
                <td><span class="day-number">18</span>
                  <button class="event" data-title="Неделя террора" data-when="16 - 23 октября" data-where="болота Манчак" data-text="День, когда на болотах было обнаружено первое растерзанное тело. Ругару терроризует болота в течении недели. Кемпинг и туристические экскурсии следовало бы отложить, но остались смельчаки, что не склонны менять планы." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span>
                  </button></td>
                <td><span class="day-number">19</span>
                  <button class="event" data-title="Неделя террора" data-when="16 - 23 октября" data-where="болота Манчак" data-text="День, когда на болотах было обнаружено первое растерзанное тело. Ругару терроризует болота в течении недели. Кемпинг и туристические экскурсии следовало бы отложить, но остались смельчаки, что не склонны менять планы." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span>
                  </button></td>
              </tr>
              <tr>
                <td><span class="day-number">20</span>
                  <button class="event" data-title="Неделя террора" data-when="16 - 23 октября" data-where="болота Манчак" data-text="День, когда на болотах было обнаружено первое растерзанное тело. Ругару терроризует болота в течении недели. Кемпинг и туристические экскурсии следовало бы отложить, но остались смельчаки, что не склонны менять планы." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span>
                  </button></td>
                <td><span class="day-number">21</span>
                  <button class="event" data-title="Неделя террора" data-when="16 - 23 октября" data-where="болота Манчак" data-text="День, когда на болотах было обнаружено первое растерзанное тело. Ругару терроризует болота в течении недели. Кемпинг и туристические экскурсии следовало бы отложить, но остались смельчаки, что не склонны менять планы." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span>
                  </button></td>
                <td><span class="day-number">22</span>
                  <button class="event" data-title="Неделя террора" data-when="16 - 23 октября" data-where="болота Манчак" data-text="День, когда на болотах было обнаружено первое растерзанное тело. Ругару терроризует болота в течении недели. Кемпинг и туристические экскурсии следовало бы отложить, но остались смельчаки, что не склонны менять планы." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span>
                  </button></td>
                <td><span class="day-number">23</span>
                  <button class="event" data-title="Неделя террора" data-when="16 - 23 октября" data-where="болота Манчак" data-text="День, когда на болотах было обнаружено первое растерзанное тело. Ругару терроризует болота в течении недели. Кемпинг и туристические экскурсии следовало бы отложить, но остались смельчаки, что не склонны менять планы." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span>
                  </button></td>
                <td><span class="day-number">24</span></td>
                <td><span class="day-number">25</span></td>
                <td><span class="day-number">26</span></td>
              </tr>
              <tr>
                <td><span class="day-number">27</span></td>
                <td><span class="day-number">28</span></td>
                <td><span class="day-number">29</span></td>
                <td><span class="day-number">30</span></td>
                <td><span class="day-number">31</span>
                  <button class="event" data-title="Krewe of BOO!" data-when="31 октября, ночь" data-where="улицы Нового Орлеана" data-text="Хэллоуин в Новом Орлеане всегда был особенным, но 2025-й обещает переписать правила игры. Krewe of BOO! выходит на улицы города: мистические платформы, колдовской джаз и маски, за которыми может скрываться кто угодно: сосед с Мариньи, древний дух с Миссисипи или существо, которое ещё вчера боялось показать клыки." aria-haspopup="dialog">
                    <span class="dot" aria-hidden="true"></span> Krewe of BOO!
                  </button>
                </td>
                <td class="is-out"></td>
                <td class="is-out"></td>
              </tr>
            </tbody>
          </table>
        </section>
      </div>

      <!-- мироописание от духа -->
      <div class="info-panel" id="infoPanel" aria-live="polite" aria-atomic="true" role="dialog" aria-modal="false">
        <div class="close-btn" id="panelClose">— закрыть —</div>
        <div class="info-panel__content">
          <h5 id="panelTitle">Заголовок</h5>
          <em id="panelMeta">Когда и где</em>
          <div id="panelBody">Текст</div>
        </div>
      </div>
    </div>
  </div>

  <script>
    (function(){
      // === ЭЛЕМЕНТЫ ===
      const calendar = document.getElementById('calendar');
      const panel = document.getElementById('infoPanel');
      const panelClose = document.getElementById('panelClose');
      const pTitle = document.getElementById('panelTitle');
      const pMeta = document.getElementById('panelMeta');
      const pBody = document.getElementById('panelBody');

      let currentTrigger = null;

      // === ОТКРЫТИЕ ПАНЕЛИ ===
      function openFromTrigger(btn){
        currentTrigger = btn;
        pTitle.textContent = btn.dataset.title || btn.textContent.trim();
        const whenTxt = btn.dataset.when ? btn.dataset.when : '';
        const whereTxt = btn.dataset.where ? (whenTxt ? ' · ' : '') + btn.dataset.where : '';
        pMeta.textContent = (whenTxt + whereTxt).trim();
        pBody.textContent = btn.dataset.text || '';
        panel.classList.add('is-open');
        panel.setAttribute('aria-modal','true');
        panelClose.focus();
      }

      // === ЗАКРЫТИЕ ПАНЕЛИ ===
      function closePopover(){
        panel.classList.remove('is-open');
        panel.setAttribute('aria-modal','false');
        if (currentTrigger) currentTrigger.focus();
      }

      // === СЛУШАТЕЛИ ===
      calendar.addEventListener('click', (e)=>{
        const btn = e.target.closest('.event');
        if (!btn) return;
        openFromTrigger(btn);
      });

      panelClose.addEventListener('click', closePopover);
      document.addEventListener('keydown', (e)=>{ if (e.key === 'Escape') closePopover(); });

      // Быстрое копирование по двойному клику по заголовку
      pTitle.addEventListener('dblclick', async ()=>{
        const text = `${pTitle.textContent}\n${pMeta.textContent}\n\n${pBody.textContent}`.trim();
        try { await navigator.clipboard.writeText(text); } catch(e){}
      });

      // === Самопроверка/"тесты" в консоли ===
      (function selfTest(){
        const results = [];
        const reqIds = ['calendar','infoPanel','panelClose','panelTitle','panelMeta','panelBody'];
        const missing = reqIds.filter(id => !document.getElementById(id));
        results.push(['IDs exist', missing.length===0, missing.length ? ('missing: '+missing.join(', ')) : 'ok']);
        const eventsCount = document.querySelectorAll('.event').length;
        results.push(['Events present', eventsCount>0, 'count='+eventsCount]);
        console.groupCollapsed('%cCalendar self-test','background:#0f1630;color:#cfe0ff;padding:2px 6px;border-radius:6px');
        results.forEach(([name, ok, msg])=> console[ok?'log':'warn'](`${name}: ${ok?'OK':'FAIL'} (${msg})`));
        console.groupEnd();
        if (location.hash === '#test' && eventsCount){
          const first = document.querySelector('.event');
          openFromTrigger(first);
          setTimeout(closePopover, 1200);
        }
      })();
    })();
  </script>
</body>
</html>
[/html]
Все описанные выше события можно использовать для личных отыгрышей.

+5


Вы здесь » Unholy Mess » Veritas occultatur in tenebris » Сюжет