diff --git a/submissions/betterPugliaSalute/_locales/en/messages.json b/submissions/betterPugliaSalute/_locales/en/messages.json new file mode 100644 index 00000000..48cf1e3e --- /dev/null +++ b/submissions/betterPugliaSalute/_locales/en/messages.json @@ -0,0 +1,38 @@ +{ + "tab_rd": { + "message": "RD" + }, + "future_feature_tab": { + "message": "Coming Soon" + }, + "rd_title": { + "message": "Dematerialized Prescription" + }, + "open": { + "message": "Open" + }, + "rd_description": { + "message": "Automatically fill in the site fields to save time" + }, + "cf_label": { + "message": "Tax Code" + }, + "cfid_label": { + "message": "Health Card ID" + }, + "phone_label": { + "message": "Phone Number" + }, + "email_label": { + "message": "Email" + }, + "save_button": { + "message": "Save" + }, + "coming_soon_title": { + "message": "Coming Soon" + }, + "coming_soon_text": { + "message": "Future feature under development." + } +} diff --git a/submissions/betterPugliaSalute/_locales/it/messages.json b/submissions/betterPugliaSalute/_locales/it/messages.json new file mode 100644 index 00000000..cf1203ec --- /dev/null +++ b/submissions/betterPugliaSalute/_locales/it/messages.json @@ -0,0 +1,38 @@ +{ + "tab_rd": { + "message": "RD" + }, + "future_feature_tab": { + "message": "Prossimamente" + }, + "rd_title": { + "message": "Ricetta Dematerializzata" + }, + "open": { + "message": "Apri" + }, + "rd_description": { + "message": "Riempi automaticamente i campi del sito per risparmiare tempo" + }, + "cf_label": { + "message": "Codice Fiscale" + }, + "cfid_label": { + "message": "ID Tessera Sanitaria" + }, + "phone_label": { + "message": "Numero di Telefono" + }, + "email_label": { + "message": "Email" + }, + "save_button": { + "message": "Salva" + }, + "coming_soon_title": { + "message": "In arrivo" + }, + "coming_soon_text": { + "message": "Funzionalità futura in fase di sviluppo." + } +} \ No newline at end of file diff --git a/submissions/betterPugliaSalute/assets/pugliasalute-128.png b/submissions/betterPugliaSalute/assets/pugliasalute-128.png new file mode 100644 index 00000000..35209dd5 Binary files /dev/null and b/submissions/betterPugliaSalute/assets/pugliasalute-128.png differ diff --git a/submissions/betterPugliaSalute/assets/pugliasalute-16.png b/submissions/betterPugliaSalute/assets/pugliasalute-16.png new file mode 100644 index 00000000..7f8efc63 Binary files /dev/null and b/submissions/betterPugliaSalute/assets/pugliasalute-16.png differ diff --git a/submissions/betterPugliaSalute/assets/pugliasalute-48.png b/submissions/betterPugliaSalute/assets/pugliasalute-48.png new file mode 100644 index 00000000..aa1c0585 Binary files /dev/null and b/submissions/betterPugliaSalute/assets/pugliasalute-48.png differ diff --git a/submissions/betterPugliaSalute/manifest.json b/submissions/betterPugliaSalute/manifest.json new file mode 100644 index 00000000..e4e07d19 --- /dev/null +++ b/submissions/betterPugliaSalute/manifest.json @@ -0,0 +1,38 @@ +{ + "manifest_version": 3, + "name": "betterPugliaSalute", + "version": "0.1.0", + "description": "An extension that enhances the Apulian Sanity website.", + "permissions": [ + "activeTab", + "storage" + ], + "default_locale": "it", + "host_permissions": [ + "https://www.sanita.puglia.it/*" + ], + "action": { + "default_popup": "popup.html", + "default_icon": "assets/pugliasalute-128.png" + }, + "content_scripts": [ + { + "matches": [ + "https://www.sanita.puglia.it/*" + ], + "js": [ + "scripts/content.js" + ] + } + ], + "icons": { + "16": "assets/pugliasalute-16.png", + "48": "assets/pugliasalute-48.png", + "128": "assets/pugliasalute-128.png" + }, + "browser_specific_settings": { + "gecko": { + "id": "betterpugliasalute@crookedog.it" + } + } +} \ No newline at end of file diff --git a/submissions/betterPugliaSalute/popup.html b/submissions/betterPugliaSalute/popup.html new file mode 100644 index 00000000..27d47a65 --- /dev/null +++ b/submissions/betterPugliaSalute/popup.html @@ -0,0 +1,53 @@ + + + + + + + Puglia Salute + + + + + + +
+ + +
+ +
+
+

+ +
+

+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+ +
+

+

+
+ + + + \ No newline at end of file diff --git a/submissions/betterPugliaSalute/scripts/browser-polyfill.min.js b/submissions/betterPugliaSalute/scripts/browser-polyfill.min.js new file mode 100644 index 00000000..37f6ee9c --- /dev/null +++ b/submissions/betterPugliaSalute/scripts/browser-polyfill.min.js @@ -0,0 +1,8 @@ +(function(a,b){if("function"==typeof define&&define.amd)define("webextension-polyfill",["module"],b);else if("undefined"!=typeof exports)b(module);else{var c={exports:{}};b(c),a.browser=c.exports}})("undefined"==typeof globalThis?"undefined"==typeof self?this:self:globalThis,function(a){"use strict";if(!globalThis.chrome?.runtime?.id)throw new Error("This script should only be loaded in a browser extension.");if("undefined"==typeof globalThis.browser||Object.getPrototypeOf(globalThis.browser)!==Object.prototype){a.exports=(a=>{const b={alarms:{clear:{minArgs:0,maxArgs:1},clearAll:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getAll:{minArgs:0,maxArgs:0}},bookmarks:{create:{minArgs:1,maxArgs:1},get:{minArgs:1,maxArgs:1},getChildren:{minArgs:1,maxArgs:1},getRecent:{minArgs:1,maxArgs:1},getSubTree:{minArgs:1,maxArgs:1},getTree:{minArgs:0,maxArgs:0},move:{minArgs:2,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeTree:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}},browserAction:{disable:{minArgs:0,maxArgs:1,fallbackToNoCallback:!0},enable:{minArgs:0,maxArgs:1,fallbackToNoCallback:!0},getBadgeBackgroundColor:{minArgs:1,maxArgs:1},getBadgeText:{minArgs:1,maxArgs:1},getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},openPopup:{minArgs:0,maxArgs:0},setBadgeBackgroundColor:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setBadgeText:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setIcon:{minArgs:1,maxArgs:1},setPopup:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setTitle:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},browsingData:{remove:{minArgs:2,maxArgs:2},removeCache:{minArgs:1,maxArgs:1},removeCookies:{minArgs:1,maxArgs:1},removeDownloads:{minArgs:1,maxArgs:1},removeFormData:{minArgs:1,maxArgs:1},removeHistory:{minArgs:1,maxArgs:1},removeLocalStorage:{minArgs:1,maxArgs:1},removePasswords:{minArgs:1,maxArgs:1},removePluginData:{minArgs:1,maxArgs:1},settings:{minArgs:0,maxArgs:0}},commands:{getAll:{minArgs:0,maxArgs:0}},contextMenus:{remove:{minArgs:1,maxArgs:1},removeAll:{minArgs:0,maxArgs:0},update:{minArgs:2,maxArgs:2}},cookies:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:1,maxArgs:1},getAllCookieStores:{minArgs:0,maxArgs:0},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},devtools:{inspectedWindow:{eval:{minArgs:1,maxArgs:2,singleCallbackArg:!1}},panels:{create:{minArgs:3,maxArgs:3,singleCallbackArg:!0},elements:{createSidebarPane:{minArgs:1,maxArgs:1}}}},downloads:{cancel:{minArgs:1,maxArgs:1},download:{minArgs:1,maxArgs:1},erase:{minArgs:1,maxArgs:1},getFileIcon:{minArgs:1,maxArgs:2},open:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},pause:{minArgs:1,maxArgs:1},removeFile:{minArgs:1,maxArgs:1},resume:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},show:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},extension:{isAllowedFileSchemeAccess:{minArgs:0,maxArgs:0},isAllowedIncognitoAccess:{minArgs:0,maxArgs:0}},history:{addUrl:{minArgs:1,maxArgs:1},deleteAll:{minArgs:0,maxArgs:0},deleteRange:{minArgs:1,maxArgs:1},deleteUrl:{minArgs:1,maxArgs:1},getVisits:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1}},i18n:{detectLanguage:{minArgs:1,maxArgs:1},getAcceptLanguages:{minArgs:0,maxArgs:0}},identity:{launchWebAuthFlow:{minArgs:1,maxArgs:1}},idle:{queryState:{minArgs:1,maxArgs:1}},management:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:0,maxArgs:0},getSelf:{minArgs:0,maxArgs:0},setEnabled:{minArgs:2,maxArgs:2},uninstallSelf:{minArgs:0,maxArgs:1}},notifications:{clear:{minArgs:1,maxArgs:1},create:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:0},getPermissionLevel:{minArgs:0,maxArgs:0},update:{minArgs:2,maxArgs:2}},pageAction:{getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},hide:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setIcon:{minArgs:1,maxArgs:1},setPopup:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setTitle:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},show:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},permissions:{contains:{minArgs:1,maxArgs:1},getAll:{minArgs:0,maxArgs:0},remove:{minArgs:1,maxArgs:1},request:{minArgs:1,maxArgs:1}},runtime:{getBackgroundPage:{minArgs:0,maxArgs:0},getPlatformInfo:{minArgs:0,maxArgs:0},openOptionsPage:{minArgs:0,maxArgs:0},requestUpdateCheck:{minArgs:0,maxArgs:0},sendMessage:{minArgs:1,maxArgs:3},sendNativeMessage:{minArgs:2,maxArgs:2},setUninstallURL:{minArgs:1,maxArgs:1}},sessions:{getDevices:{minArgs:0,maxArgs:1},getRecentlyClosed:{minArgs:0,maxArgs:1},restore:{minArgs:0,maxArgs:1}},storage:{local:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},managed:{get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1}},sync:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}}},tabs:{captureVisibleTab:{minArgs:0,maxArgs:2},create:{minArgs:1,maxArgs:1},detectLanguage:{minArgs:0,maxArgs:1},discard:{minArgs:0,maxArgs:1},duplicate:{minArgs:1,maxArgs:1},executeScript:{minArgs:1,maxArgs:2},get:{minArgs:1,maxArgs:1},getCurrent:{minArgs:0,maxArgs:0},getZoom:{minArgs:0,maxArgs:1},getZoomSettings:{minArgs:0,maxArgs:1},goBack:{minArgs:0,maxArgs:1},goForward:{minArgs:0,maxArgs:1},highlight:{minArgs:1,maxArgs:1},insertCSS:{minArgs:1,maxArgs:2},move:{minArgs:2,maxArgs:2},query:{minArgs:1,maxArgs:1},reload:{minArgs:0,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeCSS:{minArgs:1,maxArgs:2},sendMessage:{minArgs:2,maxArgs:3},setZoom:{minArgs:1,maxArgs:2},setZoomSettings:{minArgs:1,maxArgs:2},update:{minArgs:1,maxArgs:2}},topSites:{get:{minArgs:0,maxArgs:0}},webNavigation:{getAllFrames:{minArgs:1,maxArgs:1},getFrame:{minArgs:1,maxArgs:1}},webRequest:{handlerBehaviorChanged:{minArgs:0,maxArgs:0}},windows:{create:{minArgs:0,maxArgs:1},get:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:1},getCurrent:{minArgs:0,maxArgs:1},getLastFocused:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}}};if(0===Object.keys(b).length)throw new Error("api-metadata.json has not been included in browser-polyfill");class c extends WeakMap{constructor(a,b=void 0){super(b),this.createItem=a}get(a){return this.has(a)||this.set(a,this.createItem(a)),super.get(a)}}const d=a=>a&&"object"==typeof a&&"function"==typeof a.then,e=(b,c)=>(...d)=>{a.runtime.lastError?b.reject(new Error(a.runtime.lastError.message)):c.singleCallbackArg||1>=d.length&&!1!==c.singleCallbackArg?b.resolve(d[0]):b.resolve(d)},f=a=>1==a?"argument":"arguments",g=(a,b)=>function(c,...d){if(d.lengthb.maxArgs)throw new Error(`Expected at most ${b.maxArgs} ${f(b.maxArgs)} for ${a}(), got ${d.length}`);return new Promise((f,g)=>{if(b.fallbackToNoCallback)try{c[a](...d,e({resolve:f,reject:g},b))}catch(e){console.warn(`${a} API method doesn't seem to support the callback parameter, `+"falling back to call it without a callback: ",e),c[a](...d),b.fallbackToNoCallback=!1,b.noCallback=!0,f()}else b.noCallback?(c[a](...d),f()):c[a](...d,e({resolve:f,reject:g},b))})},h=(a,b,c)=>new Proxy(b,{apply(b,d,e){return c.call(d,a,...e)}});let i=Function.call.bind(Object.prototype.hasOwnProperty);const j=(a,b={},c={})=>{let d=Object.create(null),e=Object.create(a);return new Proxy(e,{has(b,c){return c in a||c in d},get(e,f){if(f in d)return d[f];if(!(f in a))return;let k=a[f];if("function"==typeof k){if("function"==typeof b[f])k=h(a,a[f],b[f]);else if(i(c,f)){let b=g(f,c[f]);k=h(a,a[f],b)}else k=k.bind(a);}else if("object"==typeof k&&null!==k&&(i(b,f)||i(c,f)))k=j(k,b[f],c[f]);else if(i(c,"*"))k=j(k,b[f],c["*"]);else return Object.defineProperty(d,f,{configurable:!0,enumerable:!0,get(){return a[f]},set(b){a[f]=b}}),k;return d[f]=k,k},set(b,c,e){return c in d?d[c]=e:a[c]=e,!0},defineProperty(a,b,c){return Reflect.defineProperty(d,b,c)},deleteProperty(a,b){return Reflect.deleteProperty(d,b)}})},k=a=>({addListener(b,c,...d){b.addListener(a.get(c),...d)},hasListener(b,c){return b.hasListener(a.get(c))},removeListener(b,c){b.removeListener(a.get(c))}}),l=new c(a=>"function"==typeof a?function(b){const c=j(b,{},{getContent:{minArgs:0,maxArgs:0}});a(c)}:a),m=new c(a=>"function"==typeof a?function(b,c,e){let f,g,h=!1,i=new Promise(a=>{f=function(b){h=!0,a(b)}});try{g=a(b,c,f)}catch(a){g=Promise.reject(a)}const j=!0!==g&&d(g);if(!0!==g&&!j&&!h)return!1;const k=a=>{a.then(a=>{e(a)},a=>{let b;b=a&&(a instanceof Error||"string"==typeof a.message)?a.message:"An unexpected error occurred",e({__mozWebExtensionPolyfillReject__:!0,message:b})}).catch(a=>{console.error("Failed to send onMessage rejected reply",a)})};return j?k(g):k(i),!0}:a),n=({reject:b,resolve:c},d)=>{a.runtime.lastError?a.runtime.lastError.message==="The message port closed before a response was received."?c():b(new Error(a.runtime.lastError.message)):d&&d.__mozWebExtensionPolyfillReject__?b(new Error(d.message)):c(d)},o=(a,b,c,...d)=>{if(d.lengthb.maxArgs)throw new Error(`Expected at most ${b.maxArgs} ${f(b.maxArgs)} for ${a}(), got ${d.length}`);return new Promise((a,b)=>{const e=n.bind(null,{resolve:a,reject:b});d.push(e),c.sendMessage(...d)})},p={devtools:{network:{onRequestFinished:k(l)}},runtime:{onMessage:k(m),onMessageExternal:k(m),sendMessage:o.bind(null,"sendMessage",{minArgs:1,maxArgs:3})},tabs:{sendMessage:o.bind(null,"sendMessage",{minArgs:2,maxArgs:3})}},q={clear:{minArgs:1,maxArgs:1},get:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}};return b.privacy={network:{"*":q},services:{"*":q},websites:{"*":q}},j(a,p,b)})(chrome)}else a.exports=globalThis.browser}); +//# sourceMappingURL=browser-polyfill.min.js.map + +// webextension-polyfill v.0.10.0 (https://github.com/mozilla/webextension-polyfill) + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ diff --git a/submissions/betterPugliaSalute/scripts/content.js b/submissions/betterPugliaSalute/scripts/content.js new file mode 100644 index 00000000..dc1ade0f --- /dev/null +++ b/submissions/betterPugliaSalute/scripts/content.js @@ -0,0 +1,68 @@ +if (typeof browser === 'undefined') { + window.browser = chrome; +} +const STORAGE_KEY = 'rdFormData'; + +// This function is from https://stackoverflow.com/questions/5525071/how-to-wait-until-an-element-exists but I modified it +const awaitElement = (selector) => + new Promise((resolve) => { + const interval = setInterval(() => { + const element = document.querySelector(selector); + if (element) { + clearInterval(interval); + resolve(element); + } + }, 100); + setTimeout(() => { + clearInterval(interval); + resolve(null); + }, 10000); + }); + +// I hate Angular +function fillAndTrigger(element, value) { + if (element && value) { + element.value = value; + element.dispatchEvent(new Event('input', { bubbles: true })); + element.dispatchEvent(new Event('change', { bubbles: true })); + } +} + +async function autofillForm() { + const result = await browser.storage.local.get(STORAGE_KEY); + const data = result[STORAGE_KEY]; + + if (!data || !data.cf || !data.cfid) { + return; + } + + const accessButton = await awaitElement('a.buttonaccesso_disattivo'); + if (accessButton) { + accessButton.click(); + } + + const cfInput = await awaitElement('[name="codiceFiscale"]'); + const cfidInput = await awaitElement('[name="numeroTessera"]'); + + if (cfInput && cfidInput) { + fillAndTrigger(cfInput, data.cf); + fillAndTrigger(cfidInput, data.cfid); + + const firstSubmitButton = cfInput.closest('form').querySelector('button.button'); + if (firstSubmitButton) { + firstSubmitButton.click(); + } + } + + const phoneInput = await awaitElement('[name="recapitoTelefonico"]'); + const emailInput = await awaitElement('[name="email"]'); + + fillAndTrigger(phoneInput, data.phone); + fillAndTrigger(emailInput, data.email); +} + +// TODO: add more features +// and then move this to a separate file +if (window.location.hash.startsWith('#/RicercaPrenotazioneDematerializzata')) { + autofillForm(); +} \ No newline at end of file diff --git a/submissions/betterPugliaSalute/scripts/popup.js b/submissions/betterPugliaSalute/scripts/popup.js new file mode 100644 index 00000000..b8066d1f --- /dev/null +++ b/submissions/betterPugliaSalute/scripts/popup.js @@ -0,0 +1,58 @@ +const STORAGE_KEY = 'rdFormData'; + +document.querySelectorAll('.tabs button').forEach(button => { + button.addEventListener('click', () => { + document.querySelectorAll('.tabs button').forEach(btn => btn.classList.remove('active')); + document.querySelectorAll('.tab-content').forEach(tab => tab.classList.remove('active')); + button.classList.add('active'); + document.querySelector(`#${button.dataset.tab}`).classList.add('active'); + }); +}); + +document.querySelector('#open-rd').addEventListener('click', () => { + window.browser.tabs.create({ + url: 'https://www.sanita.puglia.it/servizialcittadino/#/RicercaPrenotazioneDematerializzata?azienda=regionale' + }); +}); + +document.querySelectorAll('[data-i18n]').forEach(el => { + const msg = window.browser.i18n.getMessage(el.dataset.i18n); + if (msg) el.textContent = msg; +}); + +function formDataToObject(formData) { + const data = {}; + for (const [key, value] of formData.entries()) { + data[key] = value; + } + return data; +} + +document.getElementById('rd-form').addEventListener('submit', async (event) => { + event.preventDefault(); + const formData = new FormData(event.target); + + try { + const data = formDataToObject(formData); + await browser.storage.local.set({ [STORAGE_KEY]: data }); + } catch (e) { + console.error('Error saving form data:', e); + } +}); + +(async () => { + try { + const result = await browser.storage.local.get(STORAGE_KEY); + const data = result[STORAGE_KEY] || {}; + const form = document.getElementById('rd-form'); + if (!form) return; + + for (const field of form.elements) { + if (field.name && data[field.name] !== undefined) { + field.value = data[field.name]; + } + } + } catch (e) { + console.error('Error loading form data:', e); + } +})(); \ No newline at end of file diff --git a/submissions/betterPugliaSalute/style.css b/submissions/betterPugliaSalute/style.css new file mode 100644 index 00000000..952ffc3b --- /dev/null +++ b/submissions/betterPugliaSalute/style.css @@ -0,0 +1,149 @@ +body { + font-family: Arial, sans-serif; + width: 300px; + padding: 10px; + + --main-c: #dd628d; + --main-c-light: #f0b2d1; + --main-c-dark: #a74c6b; + --main-c-text: #ffffff; + --main-c-text-light: #f0f0f0; + --main-c-text-dark: #000000; + + --background: #ffdddd; + --background-text: #423838; + + background-color: var(--background); + color: var(--background-text); +} + +.tabs { + display: flex; + margin-bottom: 10px; +} + +.tabs>button { + flex: 1; + padding: 8px; + border: none; + background-color: var(--main-c-light); + cursor: pointer; + + transition: all .4s; + + &:first-of-type { + border-top-left-radius: 16px; + border-bottom-left-radius: 16px; + } + + &:last-of-type { + border-top-right-radius: 16px; + border-bottom-right-radius: 16px; + } + + &:hover { + background-color: var(--main-c-dark); + color: white; + } + + &.active { + background-color: var(--main-c); + color: white; + } +} + +div.title { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + + text-align: center; +} + +div.title>button { + padding: 4px 12px; + background-color: var(--main-c); + color: white; + border: none; + border-radius: 12px; + cursor: pointer; + + &:hover { + background-color: var(--main-c-dark); + transition: all .4s; + } +} + +.tab-content { + display: none; + + &.active { + display: block; + } +} + +#rd > p { + margin: 0; + padding: 0; + color: var(--main-c-text-dark); +} + + +form { + display: flex; + flex-direction: column; + gap: 8px; + margin-top: 10px; +} + +form > .value { + display: flex; + flex-direction: column; +} + +form > .value label { + margin-bottom: -1px; + margin-left: 6px; + font-weight: bold; +} +form > .value input { + padding: 4px 6px; + border: 1px solid var(--main-c); + border-radius: 8px; + background-color: var(--main-c-light); + color: var(--main-c-text-dark); + + transition: all .4s; + + &:focus { + border-color: var(--main-c-dark); + outline: none; + background-color: var(--main-c-text-light); + color: var(--main-c-text-dark); + } + &::placeholder { + color: var(--main-c-text-dark); + } +} + +form > button { + padding-block: 6px; + background-color: var(--main-c); + color: var(--main-c-text); + border: none; + border-radius: 16px; + cursor: pointer; + + max-width: fit-content; + padding-inline: 48px; + + transition: all .4s; + + margin-inline: auto; + + &:hover { + background-color: var(--main-c-dark); + color: var(--main-c-text-light); + } +}