Полезные материалы
Сообщений 1 страница 3 из 3
Поделиться22025-06-28 09:52:12
Шаблонизатор хронологии
Рекомендации по использованию
Когда закончите, сохраните полученный формат и список эпизодов, чтобы в дальнейшем удобно менять и добавлять пункты.
Вы можете хранить их прямо в вашем сообщении, спрятав в теге:Код:[blockHidden] *ваш контент* [/blockHidden]Тогда техническая информация не будет отображаться 🤖
Пример формата:
Код:[table] {{episodeStart}} [tr valign=top] [td width=15% bgcolor={{isFinished ? #cecece : #ffffff }}][font=Palatino Linotype][i][color=#6f474e]{{date}}[/color] [color=gray] {{place}} [/color][/i][/font][/td] [td bgcolor={{isFinished ? #cecece : #ffffff }}][url={{link}}]{{episodeName}} — {{users}}[/url] {{descr}}[/td] [/tr] {{episodeEnd}} [table]
[html]
<div class="fillingForm">
<label class="fillingCategoryRadio"><input type="radio" id="content" name="fillingCategoryRadio" checked /><span>Эпизоды</span></label>
<label class="fillingCategoryRadio"><input type="radio" id="format" name="fillingCategoryRadio" /><span>Формат</span></label>
<label class="fillingCategoryRadio"><input type="radio" id="import" name="fillingCategoryRadio" /><span>Импорт</span></label>
<div class="instructionBlock content">
<h2 class="instructionHeading">Список эпизодов</h2>
<div id="episodeContainer">
<div class="episode">
<input type="button" id="deleteEpisode0" class="deleteButton" value="">
<div class="fillingLine">
<label for="link0" class="labelDescr">Ссылка:</label>
<input type="text" id="link0" name="link0" value="">
</div>
<div class="fillingLine">
<label for="episodeName0" class="labelDescr">Название:</label>
<input type="text" id="episodeName0" name="episodeName0" value="">
</div>
<div class="fillingLine">
<label for="users0" class="labelDescr">Участники:</label>
<input type="text" id="users0" name="users0" placeholder="Необязательное поле">
</div>
<div class="fillingLine">
<label for="date0" class="labelDescr">Дата:</label>
<input type="text" id="date0" name="date0" placeholder="Необязательное поле">
</div>
<div class="fillingLine">
<label for="place0" class="labelDescr">Место:</label>
<input type="text" id="place0" name="place0" placeholder="Необязательное поле">
</div>
<label for="episodeDescr0" class="labelDescr">Краткое описание:</label>
<textarea id="episodeDescr0" name="episodeDescr0" rows="3" placeholder="Необязательное поле"></textarea>
<label for="isFinished0" class="isFinished">
<input type="checkbox" id="isFinished0" name="isFinished0" />
<span>Закончен</span>
</label>
</div>
</div>
<div class="formButtons">
<input type="button" id="addNewEpisode" value="Добавить эпизод">
</div>
</div>
<div class="instructionBlock format">
<h2 class="instructionHeading">Формат</h2>
<span>
В формате вставляйте контент следующим образом:<br>
{{episodeStart}} — {{episodeEnd}} — эпизод (то, что будет повторяться для каждого эпизода) заключаем внутрь этого блока<br>
{{isFinished ? #cecece : #ffffff }} — если завершен, то возьмется первое значение, если не завершен, то второе<br>
{{date}} — поле из "дата"<br>
{{place}} — поле из локации<br>
{{link}} — ссылка<br>
{{episodeName}} — название эпизода<br>
{{users}} — список участников<br>
{{descr}} — описание<br>
<br>
</span>
<textarea id="formatValue" rows="30">Ваш формат</textarea>
</div>
<div class="instructionBlock import">
<h2 class="instructionHeading">Импорт данных</h2>
<span>
Вставьте сюда список эпизодов, который сохранили с помощью кнопки "Скопировать список эпизодов".<br>
Все эпизоды будут импортированы в первую вкладку, чтобы вы могли продолжить заполнение.<br>
Для первого импорта из кода, когда нет JSON, можете попробовать воспользоваться ИИ (chatgpt, gemini, яндекс и т.д.).<br>
<div class="formButtons">
<input type="button" id="promptCopy" value="Скопировать пример запроса">
</div>
<br>
</span>
<textarea id="episodeListValue" rows="30"></textarea>
<div class="formButtons">
<input type="button" id="importButton" value="Импортировать">
</div>
</div>
</div>
<div class="formButtons">
<input type="button" id="formatResult" value="Скопировать формат">
<input type="button" id="episodeListResult" value="Скопировать список эпизодов">
<input type="button" id="fullResult" value="Скопировать результат">
</div>
<style>
h2.instructionHeading {
font-size: 16px;
font-family: 'Palatino Linotype';
font-weight: bold;
letter-spacing: 1px;
}
.labelDescr {
display: block;
margin: 9px 0px 1px 0px;
}
.instructionBlock {
text-align: left;
margin: 10px 0 !important;
padding: 14px 14px 12px 14px !important;
border: 1px solid var(--pinkBorder);
background: var(--qBG);
border-radius: 4px;
}
.instructionBlock input[type="text"], .instructionBlock textarea {
width: calc(100% - 10px) !important;
}
label.isFinished {
margin: 10px 0 0 0;
display: block;
}
input#isFinished {
accent-color: var(--darkpinkText);
}
label.fillingCategoryRadio {
border-radius: 16px;
border: 1px solid var(--pinkBorder);
background: var(--lightBG);
padding: 2px 6px;
display: inline-block;
margin: 0px 4px 5px 0px;
}
label.fillingCategoryRadio:has(input:checked) {
background: var(--pinkBorder);
color: #fff;
}
.fillingCategoryRadio input[type="radio"] {
display: none;
}
label.fillingCategoryRadio {
cursor: pointer;
}
.import, .format, .content { display: none; }
.fillingCategoryRadio:has(#import:checked) ~ .import {
display: block !important;
}
.fillingCategoryRadio:has(#content:checked) ~ .content {
display: block !important;
}
.fillingCategoryRadio:has(#format:checked) ~ .format {
display: block !important;
}
.fillingForm { text-align: center; }
.fillingLine {
display: flex;
gap: 10px;
margin: 5px 0px;
}
.episode {
text-align: left;
margin: 10px -15px !important;
padding: 5px 14px 7px 14px !important;
border: 1px solid var(--pinkBorder);
background: #d5d5d5;
border-radius: 4px;
}
input[type="button"].deleteButton {
font: normal 13px 'FontAwesomeSolid' !important;
position: absolute;
right: 15px;
}
}
</style>
<script>
let episodeCounter = 1; // Следующий ID для нового эпизода
// Функция для создания нового эпизода
function addNewEpisode() {
const episodeContainer = document.getElementById('episodeContainer');
// Создаем новый div эпизода
const newEpisode = document.createElement('div');
newEpisode.className = 'episode';
newEpisode.setAttribute('data-episode-id', episodeCounter);
newEpisode.innerHTML = `
<input type="button" class="deleteButton" value="✕">
<div class="fillingLine">
<label for="link${episodeCounter}" class="labelDescr">Ссылка:</label>
<input type="text" id="link${episodeCounter}" name="link${episodeCounter}" value="">
</div>
<div class="fillingLine">
<label for="episodeName${episodeCounter}" class="labelDescr">Название:</label>
<input type="text" id="episodeName${episodeCounter}" name="episodeName${episodeCounter}" value="">
</div>
<div class="fillingLine">
<label for="users${episodeCounter}" class="labelDescr">Участники:</label>
<input type="text" id="users${episodeCounter}" name="users${episodeCounter}" placeholder="Необязательное поле">
</div>
<div class="fillingLine">
<label for="date${episodeCounter}" class="labelDescr">Дата:</label>
<input type="text" id="date${episodeCounter}" name="date${episodeCounter}" placeholder="Необязательное поле">
</div>
<div class="fillingLine">
<label for="place${episodeCounter}" class="labelDescr">Место:</label>
<input type="text" id="place${episodeCounter}" name="place${episodeCounter}" placeholder="Необязательное поле">
</div>
<label for="episodeDescr${episodeCounter}" class="labelDescr">Краткое описание:</label>
<textarea id="episodeDescr${episodeCounter}" name="episodeDescr${episodeCounter}" rows="3" placeholder="Необязательное поле"></textarea>
<label for="isFinished${episodeCounter}" class="isFinished">
<input type="checkbox" id="isFinished${episodeCounter}" name="isFinished${episodeCounter}" />
<span>Закончен</span>
</label>
`;
// Добавляем новый эпизод в контейнер
episodeContainer.appendChild(newEpisode);
// Добавляем обработчик события для кнопки удаления
const deleteBtn = newEpisode.querySelector('.deleteButton');
deleteBtn.addEventListener('click', function() {
deleteEpisode(newEpisode);
});
episodeCounter++;
}
// Функция для удаления эпизода
function deleteEpisode(episodeElement) {
// Проверяем, что остался хотя бы один эпизод
const episodeContainer = document.getElementById('episodeContainer');
const episodes = episodeContainer.querySelectorAll('.episode');
if (episodes.length > 1) {
episodeElement.remove();
} else {
console.log('Должен остаться хотя бы один эпизод!');
}
}
// Функция для копирования формата
function copyFormat() {
const formatResult = document.getElementById('formatValue').value;
window.parent.postMessage({
eventName: 'profileCopyInfoRequest',
copyData: formatResult.trim()
}, "*");
}
// Функция для сбора данных всех эпизодов
function collectEpisodeData() {
const episodes = [];
const episodeContainer = document.getElementById('episodeContainer');
const episodeElements = episodeContainer.querySelectorAll('.episode');
episodeElements.forEach((episodeElement, index) => {
const episodeId = index; // Используем индекс как ID
const episode = {
link: document.getElementById(`link${episodeId}`)?.value || '',
episodeName: document.getElementById(`episodeName${episodeId}`)?.value || '',
users: document.getElementById(`users${episodeId}`)?.value || '',
date: document.getElementById(`date${episodeId}`)?.value || '',
place: document.getElementById(`place${episodeId}`)?.value || '',
descr: document.getElementById(`episodeDescr${episodeId}`)?.value || '',
isFinished: document.getElementById(`isFinished${episodeId}`)?.checked || false
};
// Очищаем поля от placeholder текста
Object.keys(episode).forEach(key => {
if (episode[key] === 'Необязательное поле') {
episode[key] = '';
}
});
episodes.push(episode);
});
return episodes;
}
// Функция для обработки условных выражений типа {{isFinished ? value1 : value2}}
function processConditional(template, episode) {
const conditionalRegex = /\{\{isFinished\s*\?\s*([^:]+)\s*:\s*([^}]+)\}\}/g;
return template.replace(conditionalRegex, (match, trueValue, falseValue) => {
return episode.isFinished ? trueValue.trim() : falseValue.trim();
});
}
// Функция для замены переменных в шаблоне
function replaceVariables(template, episode) {
const variables = {
'{{link}}': episode.link,
'{{episodeName}}': episode.episodeName,
'{{users}}': episode.users,
'{{date}}': episode.date,
'{{place}}': episode.place,
'{{descr}}': episode.descr
};
let result = template;
// Сначала обрабатываем условные выражения
result = processConditional(result, episode);
// Затем заменяем простые переменные
Object.keys(variables).forEach(variable => {
const regex = new RegExp(variable.replace(/[{}]/g, '\\$&'), 'g');
result = result.replace(regex, variables[variable]);
});
return result;
}
// Основная функция для генерации результата
function generateResult() {
const episodes = collectEpisodeData();
const formatTemplate = document.getElementById('formatValue').value;
if (!formatTemplate.trim()) {
console.log('Пожалуйста, введите формат!');
return '';
}
// Находим блоки {{episodeStart}} и {{episodeEnd}}
const episodeStartRegex = /\{\{episodeStart\}\}([\s\S]*?)\{\{episodeEnd\}\}/g;
const matches = [...formatTemplate.matchAll(episodeStartRegex)];
if (matches.length === 0) {
// Если нет блоков повторения, просто заменяем переменные для первого эпизода
if (episodes.length > 0) {
return replaceVariables(formatTemplate, episodes[0]);
}
return formatTemplate;
}
let result = formatTemplate;
// Обрабатываем каждый блок повторения
matches.forEach(match => {
const fullMatch = match[0];
const episodeTemplate = match[1];
// Генерируем контент для всех эпизодов
const episodeContents = episodes.map(episode =>
replaceVariables(episodeTemplate, episode)
).join('');
// Заменяем блок {{episodeStart}}...{{episodeEnd}} на сгенерированный контент
result = result.replace(fullMatch, episodeContents);
});
return result;
}
// Обработчик для кнопки "Добавить эпизод"
document.getElementById('addNewEpisode').addEventListener('click', addNewEpisode);
// Обработчик для кнопки "Скопировать формат"
document.getElementById('formatResult').addEventListener('click', copyFormat);
// Обработчик для первой кнопки удаления (эпизод 0)
const firstDeleteBtn = document.querySelector('.deleteButton');
firstDeleteBtn.addEventListener('click', function() {
const episodeElement = firstDeleteBtn.closest('.episode');
deleteEpisode(episodeElement);
});
document.getElementById('fullResult').addEventListener('click', function() {
const result = generateResult();
window.parent.postMessage({
eventName: 'profileCopyInfoRequest',
copyData: result.trim()
}, "*");
});
document.getElementById('episodeListResult').addEventListener('click', function() {
const episodes = collectEpisodeData();
const jsonString = JSON.stringify(episodes, null, 2);
window.parent.postMessage({
eventName: 'profileCopyInfoRequest',
copyData: jsonString.trim()
}, "*");
});
// Функция для очистки всех эпизодов
function clearAllEpisodes() {
const episodeContainer = document.getElementById('episodeContainer');
episodeContainer.innerHTML = '';
episodeCounter = 0;
}
// Функция для создания эпизода с заданными данными
function createEpisodeWithData(episodeData, index) {
const episodeContainer = document.getElementById('episodeContainer');
// Создаем новый div эпизода
const newEpisode = document.createElement('div');
newEpisode.className = 'episode';
newEpisode.setAttribute('data-episode-id', index);
newEpisode.innerHTML = `
<input type="button" class="deleteButton" value="✕">
<div class="fillingLine">
<label for="link${index}" class="labelDescr">Ссылка:</label>
<input type="text" id="link${index}" name="link${index}" value="${episodeData.link || ''}">
</div>
<div class="fillingLine">
<label for="episodeName${index}" class="labelDescr">Название:</label>
<input type="text" id="episodeName${index}" name="episodeName${index}" value="${episodeData.episodeName || ''}">
</div>
<div class="fillingLine">
<label for="users${index}" class="labelDescr">Участники:</label>
<input type="text" id="users${index}" name="users${index}" value="${episodeData.users || ''}" placeholder="Необязательное поле">
</div>
<div class="fillingLine">
<label for="date${index}" class="labelDescr">Дата:</label>
<input type="text" id="date${index}" name="date${index}" value="${episodeData.date || ''}" placeholder="Необязательное поле">
</div>
<div class="fillingLine">
<label for="place${index}" class="labelDescr">Место:</label>
<input type="text" id="place${index}" name="place${index}" value="${episodeData.place || ''}" placeholder="Необязательное поле">
</div>
<label for="episodeDescr${index}" class="labelDescr">Краткое описание:</label>
<textarea id="episodeDescr${index}" name="episodeDescr${index}" rows="3" placeholder="Необязательное поле">${episodeData.descr || ''}</textarea>
<label for="isFinished${index}" class="isFinished">
<input type="checkbox" id="isFinished${index}" name="isFinished${index}" ${episodeData.isFinished ? 'checked' : ''} />
<span>Закончен</span>
</label>
`;
// Добавляем новый эпизод в контейнер
episodeContainer.appendChild(newEpisode);
// Добавляем обработчик события для кнопки удаления
const deleteBtn = newEpisode.querySelector('.deleteButton');
deleteBtn.addEventListener('click', function() {
deleteEpisode(newEpisode);
});
}
// Функция для импорта эпизодов из JSON
function importEpisodesFromJSON() {
try {
const jsonString = document.getElementById('episodeListValue').value.trim();
if (!jsonString) {
console.log('Пожалуйста, вставьте JSON данные для импорта');
return;
}
const episodesData = JSON.parse(jsonString);
if (!Array.isArray(episodesData)) {
console.log('JSON должен содержать массив эпизодов');
return;
}
if (episodesData.length === 0) {
console.log('Массив эпизодов пуст');
return;
}
// Очищаем существующие эпизоды
clearAllEpisodes();
// Создаем эпизоды из импортированных данных
episodesData.forEach((episodeData, index) => {
createEpisodeWithData(episodeData, index);
});
// Обновляем счетчик для следующих эпизодов
episodeCounter = episodesData.length;
// Переключаемся на вкладку "Эпизоды"
document.getElementById('content').checked = true;
console.log(`Успешно импортировано ${episodesData.length} эпизодов`);
} catch (error) {
console.log('Ошибка при парсинге JSON: ' + error.message);
}
}
document.getElementById('importButton').addEventListener('click', function() {
importEpisodesFromJSON();
});
document.getElementById('promptCopy').addEventListener('click', function() {
const text = `
вот формат.
[table]
{{episodeStart}}
[tr valign=top]
[td width=15% bgcolor={{isFinished ? #cecece : #ffffff }}]{{date}}
{{place}} [/td]
[td bgcolor={{isFinished ? #cecece : #ffffff }}]{{episodeName}} — {{users}}
{{descr}}[/td]
[/tr]
{{episodeEnd}}
[table]
Вот описание формата {{episodeStart}} — {{episodeEnd}} — повторяемые блоки эпизодов заключаем внутрь этого блока
{{isFinished ? #cecece : #ffffff }} — если завершен, то возьмется первое значение, если не завершен, то второе
{{date}} — поле из "дата"
{{place}} — поле из локации
{{link}} — ссылка
{{episodeName}} — название эпизода
{{users}} — список участников
{{descr}} — описание
Мне нужно, чтобы в соответствии с этим форматом ты распарсил ВСЕ эпизоды из моего кода СТРОГО В СЛЕДУЮЩЕМ ФОРМАТЕ:
[
{
"link": "ссылка",
"episodeName": "Название эпизода",
"users": "Участники",
"date": "Дата",
"place": "Место",
"descr": "Описание краткое",
"isFinished": true
}
]
Вот мой код:
`;
window.parent.postMessage({
eventName: 'profileCopyInfoRequest',
copyData: text.trim()
}, "*");
});
</script>
[/html]
Поделиться32025-06-28 09:57:02
Генератор кода для акций
Рекомендации по использованию
Вы могли заметить, что в нужных внутри сообщений со временем добавляется блок blockhidden, внутри которого находится техническая информация. Она нужна, чтобы работал автосбор акций в шапку темы, и заполняет этот блок администрация.Если взять в спойлер информацию из blockhidden (как обычно делается, когда его бронируют), то можно удалить персонажа из шапки темы.
Если хочется поменять теги, расставленные администрацией, или задать другое описание, вы можете это сделать благодаря этому генератору.
[html]<script>
// --------- input data ------------
const Gender = {
Male: { id: 'Male', name: 'Мужской' },
Female: { id: 'Female', name: 'Женский' }
};
const Activity = {
Politics: { id: 'Politics', name: 'Политики' },
Warrior: { id: 'Warrior', name: 'Воины' },
Gods: { id: 'Gods', name: 'Служители богов' },
Wizard: { id: 'Wizard', name: 'Маги' },
Kale: { id: 'Kale', name: 'Кале' },
Criminal: { id: 'Criminal', name: 'Криминал' },
};
const Race = {
Human: { id: 'Human', name: 'Люди' },
Vampire: { id: 'Vampire', name: 'Вампиры' },
Soulless: { id: 'Soulless', name: 'Бездушники' },
Aire: { id: 'Aire', name: 'Айре' },
Werewolf: { id: 'Werewolf', name: 'Перевертыши' },
Beastman: { id: 'Beastman', name: 'Зверолюди' },
};
const Aim = {
Family: { id: 'Family', name: 'Семья' },
Love: { id: 'Love', name: 'Пара' },
Friend: { id: 'Friend', name: 'Дружба' },
Enemy: { id: 'Enemy', name: 'Враги' },
Worker: { id: 'Worker', name: 'Подчиненные' },
Plot: { id: 'Plot', name: 'Сюжет' }
};
// --------- fill containers ------------
const containers = {
activity: document.querySelector('.activityContainer'),
race: document.querySelector('.raceContainer'),
gender: document.querySelector('.genderContainer'),
aim: document.querySelector('.aimContainer')
};
function checkbox(text, id, name, isChecked = '') {
return `<label class="tag"><input type="checkbox" id="${id}" name="${name}" ${isChecked} /> <span>${text}</span></label>`;
}
function radiobox(text, id, name) {
return `<label class="tag"><input type="radio" id="${id}" name="${name}" /> <span>${text}</span></label>`
}
function fillContainers(cont) {
cont.gender.innerHTML = Object.values(Gender).map(gender => radiobox(gender.name, gender.id, 'gender')).join('');
cont.aim.innerHTML = Object.values(Aim).map(aim => checkbox(aim.name, aim.id, 'aim')).join('');
cont.activity.innerHTML = Object.values(Activity).map(activity => checkbox(activity.name, activity.id, 'activity')).join('');
cont.race.innerHTML = Object.values(Race).map(race => checkbox(race.name, race.id, 'race')).join('');
}
fillContainers(containers);
// --------- USER DATA ------------
function copyResults() {
let copyContent = '';
const cyrillicName = document.getElementById('cyrillicName').value;
const cyrillicDescr = document.getElementById('cyrillicDescr').value;
const hasRoleTags = Array.from(document.getElementsByName('gender')).some(el => el.checked) ||
Array.from(document.getElementsByName('aim')).some(el => el.checked) ||
Array.from(document.getElementsByName('activity')).some(el => el.checked) ||
Array.from(document.getElementsByName('race')).some(el => el.checked);
if (hasRoleTags) {
const currentName = cyrillicName || 'Имя персонажа';
const currentDescr = cyrillicDescr || 'Описание персонажа';
const gendersTags = Array.from(document.getElementsByName('gender'));
const aimTags = Array.from(document.getElementsByName('aim'));
const activityTags = Array.from(document.getElementsByName('activity'));
const raceTags = Array.from(document.getElementsByName('race'));
const allTags = gendersTags.concat(aimTags, activityTags, raceTags);
const selectedTags = allTags
.filter(element => element.checked)
.map(element => `"${element.id}"`)
.join(', ');
const rolesForm = `{ "name": "${cyrillicName}", "tags": [ ${selectedTags} ], "descr": "${cyrillicDescr}" }`;
copyContent += `${String.fromCharCode(91)}blockHidden${String.fromCharCode(93)}${rolesForm}${String.fromCharCode(91)}/blockHidden${String.fromCharCode(93)}`;
}
window.parent.postMessage({
eventName: 'profileCopyInfoRequest',
copyData: copyContent.trim() // Удаляем лишние переносы в конце
}, "*");
};
document.getElementById('instructionResult').onclick = copyResults;
window.addEventListener("message", (event) => {
if (!event.origin.match(/oldshadows\.rusff\.me$/)) return;
if (event.data.eventName != 'fontChange') return;
$('.post-content p, .post-content div').css('font-size', event.data.fontSize + 'px');
});
</script>
<div class="instructionBlock listsInstruction" id="mainUserList">
<h2 class="instructionHeading">Скопировать шаблон</h2>
<label for="cyrillicName" class="labelDescr">Имя на кириллице:</label>
<input type="text" id="cyrillicName" name="cyrillicName">
<label for="cyrillicDescr" class="labelDescr">Краткое описание:</label>
<input type="text" id="cyrillicDescr" name="cyrillicDescr">
<br><br>
<h2 class="instructionHeading">Теги</h2>
<span class="labelDescr">Выберите теги, которые характеризуют вашу заявку:</span>
<span class="labelDescr">Пол:</span>
<div class="genderContainer"></div>
<span class="labelDescr">Деятельности:</span>
<div class="activityContainer"></div>
<span class="labelDescr">Расы:</span>
<div class="raceContainer"></div>
<span class="labelDescr">Цель заявки:</span>
<div class="aimContainer"></div>
</div>
<div class="formButtons">
<input type="button" id="instructionResult" value="Скопировать код">
</div>
<style>
h2.instructionHeading {
font-size: 16px;
font-family: 'Palatino Linotype';
font-weight: bold;
letter-spacing: 1px;
}
.labelDescr {
display: block;
margin: 9px 0px 1px 0px;
}
.instructionBlock {
text-align: left;
margin: 10px 0 !important;
padding: 14px 14px 12px 14px !important;
border: 1px solid var(--pinkBorder);
background: var(--qBG);
border-radius: 4px;
}
.instructionBlock input[type="text"] {
width: calc(100% - 10px);
}
label.hrAdd, label.npcDead {
margin: 10px 0 0 0;
display: block;
}
input#hrAdd, input.npcDead {
accent-color: var(--darkpinkText);
}
input#listsDescr {
margin-bottom: 16px;
}
label.tag {
border-radius: 16px;
border: 1px solid var(--pinkBorder);
background: var(--lightBG);
padding: 4px 8px;
display: inline-block;
margin: 0px 4px 5px 0px;
}
label.tag:has(input:checked) {
background: var(--pinkBorder);
color: #fff;
}
.tag input[type="checkbox"], .tag input[type="radio"] {
display: none;
}
label.tag {
cursor: pointer;
}
</style>[/html]