From b67263aabfe7002f0187b9739383671a6f7766c7 Mon Sep 17 00:00:00 2001 From: lilliputten Date: Wed, 10 Apr 2024 17:26:38 +0700 Subject: [PATCH 1/8] Issue #149: Renamed used modules from `billing` to `payment`. --- .../{billing => payment}/stripe_payment.html.django | 0 dds_registration/urls/payments_urls.py | 2 +- dds_registration/views/{billing_stripe.py => payment_stripe.py} | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename dds_registration/templates/dds_registration/{billing => payment}/stripe_payment.html.django (100%) rename dds_registration/views/{billing_stripe.py => payment_stripe.py} (98%) diff --git a/dds_registration/templates/dds_registration/billing/stripe_payment.html.django b/dds_registration/templates/dds_registration/payment/stripe_payment.html.django similarity index 100% rename from dds_registration/templates/dds_registration/billing/stripe_payment.html.django rename to dds_registration/templates/dds_registration/payment/stripe_payment.html.django diff --git a/dds_registration/urls/payments_urls.py b/dds_registration/urls/payments_urls.py index dc3892b1..798a18e9 100644 --- a/dds_registration/urls/payments_urls.py +++ b/dds_registration/urls/payments_urls.py @@ -1,6 +1,6 @@ from django.urls import path -from ..views.billing_stripe import payment_stripe, payment_stripe_success +from ..views.payment_stripe import payment_stripe, payment_stripe_success from ..views.payment_utils import invoice_download, receipt_download urlpatterns = [ diff --git a/dds_registration/views/billing_stripe.py b/dds_registration/views/payment_stripe.py similarity index 98% rename from dds_registration/views/billing_stripe.py rename to dds_registration/views/payment_stripe.py index 60991e4d..eccc3d32 100644 --- a/dds_registration/views/billing_stripe.py +++ b/dds_registration/views/payment_stripe.py @@ -42,7 +42,7 @@ def payment_stripe(request: HttpRequest, payment_id: int): payment.data["currency"], stripe_amount, request.user.email, {"payment_id": payment.id} ) - template = "dds_registration/billing/stripe_payment.html.django" + template = "dds_registration/payment/stripe_payment.html.django" try: membership = Membership.objects.get(user=request.user) From a53e42bb5412d94d749dbcee296327b5d4b5c8a2 Mon Sep 17 00:00:00 2001 From: lilliputten Date: Wed, 10 Apr 2024 18:55:59 +0700 Subject: [PATCH 2/8] Issue #149: Extracting email messages to tamplates (in progress): passing request parameter to message generation code, added templates for payment invoice, added email helpers. --- dds_registration/admin.py | 22 ++++----- dds_registration/core/helpers/emails.py | 26 ++++++++++ dds_registration/models.py | 48 ++++++++++++++----- .../payment/emails/invoice_event.txt.django | 15 ++++++ .../emails/invoice_membership.txt.django | 14 ++++++ dds_registration/views/event_registration.py | 2 +- dds_registration/views/membership.py | 2 +- dds_registration/views/payment_stripe.py | 2 +- 8 files changed, 106 insertions(+), 25 deletions(-) create mode 100644 dds_registration/core/helpers/emails.py create mode 100644 dds_registration/templates/dds_registration/payment/emails/invoice_event.txt.django create mode 100644 dds_registration/templates/dds_registration/payment/emails/invoice_membership.txt.django diff --git a/dds_registration/admin.py b/dds_registration/admin.py index fd20a0ac..0337b6d5 100644 --- a/dds_registration/admin.py +++ b/dds_registration/admin.py @@ -4,8 +4,8 @@ from django.contrib import admin, messages from django.contrib.admin import SimpleListFilter from django.contrib.auth.admin import UserAdmin as BaseUserAdmin -from django.db.models import Q -from django.http import HttpResponse +from django.db.models import Q, QuerySet +from django.http import HttpRequest, HttpResponse from .forms import ( EventAdminForm, @@ -42,7 +42,7 @@ def lookups(self, request, model_admin): ("0", "No"), ) - def queryset(self, request, queryset): + def queryset(self, request: HttpRequest, queryset: QuerySet): if self.value() == "1": return queryset.filter(is_staff=False, is_superuser=False) if self.value() == "0": @@ -212,9 +212,9 @@ class PaymentAdmin(admin.ModelAdmin): actions = ["mark_invoice_paid", "email_invoices", "email_receipts", "download_invoices", "download_receipts"] @admin.action(description="Mark selected invoices paid") - def mark_invoice_paid(self, request, queryset): + def mark_invoice_paid(self, request: HttpRequest, queryset: QuerySet): for obj in queryset: - obj.mark_paid() + obj.mark_paid(request) self.message_user( request, f"{queryset.count()} invoices marked as paid", @@ -222,7 +222,7 @@ def mark_invoice_paid(self, request, queryset): ) @admin.action(description="Email unpaid invoices to user") - def email_invoices(self, request, queryset): + def email_invoices(self, request: HttpRequest, queryset: QuerySet): qs = queryset.filter(status__in=("CREATED", "ISSUED")) count = qs.count() @@ -235,7 +235,7 @@ def email_invoices(self, request, queryset): return for obj in qs: - obj.email_invoice() + obj.email_invoice(request) self.message_user( request, @@ -244,7 +244,7 @@ def email_invoices(self, request, queryset): ) @admin.action(description="Download unpaid invoices") - def download_invoices(self, request, queryset): + def download_invoices(self, request: HttpRequest, queryset: QuerySet): qs = queryset.filter(status__in=("CREATED", "ISSUED")) if not qs.count(): @@ -266,7 +266,7 @@ def download_invoices(self, request, queryset): return response @admin.action(description="Email receipts for completed payments to user") - def email_receipts(self, request, queryset): + def email_receipts(self, request: HttpRequest, queryset): qs = queryset.filter(status="PAID") count = qs.count() @@ -279,7 +279,7 @@ def email_receipts(self, request, queryset): return for obj in queryset: - obj.email_receipt() + obj.email_receipt(request) self.message_user( request, f"{count} receipt(s) sent", @@ -287,7 +287,7 @@ def email_receipts(self, request, queryset): ) @admin.action(description="Download completed payment receipts") - def download_receipts(self, request, queryset): + def download_receipts(self, request: HttpRequest, queryset: QuerySet): qs = queryset.filter(status="PAID") if not qs.count(): diff --git a/dds_registration/core/helpers/emails.py b/dds_registration/core/helpers/emails.py new file mode 100644 index 00000000..1bd98ce4 --- /dev/null +++ b/dds_registration/core/helpers/emails.py @@ -0,0 +1,26 @@ +import re + + +def prepare_email_message_text(text: str) -> str: + # Remove spaces around + text = text.strip() + # Remove spaces before newlines + text = re.sub(r"\s*[\n\r]", "\n", text) + # Leave max two newlines in a row + text = re.sub(r"\n{3,}", "\n\n", text) + return text + + +def parse_email_subject_and_content(text: str) -> list[str]: + """ + Email message should contain a subject in the beginning, separated from the content by double newline. + Returns the list consisted of [subject, content] + """ + text = prepare_email_message_text(text) + return text.split('\n\n', 1) + + +__all__ = [ + prepare_email_message_text, + parse_email_subject_and_content, +] diff --git a/dds_registration/models.py b/dds_registration/models.py index b4dc2dd6..35ecc3cc 100644 --- a/dds_registration/models.py +++ b/dds_registration/models.py @@ -4,20 +4,25 @@ import random import string from datetime import date - import requests + +from fpdf import FPDF + +from django.contrib.sites.models import Site +from django.http import HttpRequest from django.conf import settings from django.contrib.auth.models import AbstractUser from django.core.exceptions import ObjectDoesNotExist from django.db import models from django.db.models import Model, Q, QuerySet from django.urls import reverse -from fpdf import FPDF +from django.template.loader import render_to_string from dds_registration.core.constants.payments import ( site_default_currency, site_supported_currencies, ) +from .core.helpers.emails import parse_email_subject_and_content from .core.constants.date_time_formats import dateFormat from .core.constants.payments import currency_emojis, payment_details_by_currency @@ -220,7 +225,7 @@ def mark_obsolete(self): ) self.save() - def mark_paid(self): + def mark_paid(self, request: HttpRequest): if self.status == "PAID": return self.status = "PAID" @@ -235,7 +240,7 @@ def mark_paid(self): ) }, ) - self.email_receipt() + self.email_receipt(request) self.save() @property @@ -285,16 +290,37 @@ def invoice_pdf(self): def receipt_pdf(self): return create_receipt_pdf_from_payment(self) - def email_invoice(self): + def email_invoice(self, request: HttpRequest): user = User.objects.get(id=self.data["user"]["id"]) # TODO: Issue #149: To extract these (and all other hardcoded here, in `send_email` methods?) texts to template files, with substiting names, urls and emails from settings or preferences values? + scheme = "https" if self.request.is_secure() else "http" + site = Site.objects.get_current() + context = { + "site": site, + "scheme": scheme, + "payment": self, + "user": user, + } if self.data["kind"] == "membership": - subject = f"DdS Membership Invoice {self.invoice_no}" - message = f"Thanks for signing up for Départ de Sentier membership! Membership fees allow us to write awesome open source code, deploy open infrastructure, and run community events without spending all our time fundraising.\n\nYour membership will run until December 31st, {user.membership.until} (Don't worry, you will get a reminder to renew for another year :).\n\nPlease find attached the membership invoice. Your membership is not in force until the bank transfer is received.\n\nYou can change your invoice details here: https://events.d-d-s.ch{reverse('membership_application')}.\n\nIf you have any questions, please contact events@d-d-s.ch." + email_template = "dds_registration/payment/emails/invoice_membership.txt.django" + # text = f""" + # DdS Membership Invoice {self.invoice_no} + # Thanks for signing up for Départ de Sentier membership! Membership fees allow us to write awesome open source code, deploy open infrastructure, and run community events without spending all our time fundraising.\n\nYour membership will run until December 31st, {user.membership.until} (Don't worry, you will get a reminder to renew for another year :).\n\nPlease find attached the membership invoice. Your membership is not in force until the bank transfer is received.\n\nYou can change your invoice details here: https://events.d-d-s.ch{reverse('membership_application')}.\n\nIf you have any questions, please contact events@d-d-s.ch. + # """ + # subject = f"DdS Membership Invoice {self.invoice_no}" + # message = f"Thanks for signing up for Départ de Sentier membership! Membership fees allow us to write awesome open source code, deploy open infrastructure, and run community events without spending all our time fundraising.\n\nYour membership will run until December 31st, {user.membership.until} (Don't worry, you will get a reminder to renew for another year :).\n\nPlease find attached the membership invoice. Your membership is not in force until the bank transfer is received.\n\nYou can change your invoice details here: https://events.d-d-s.ch{reverse('membership_application')}.\n\nIf you have any questions, please contact events@d-d-s.ch." else: - event = Event.objects.get(id=self.data["event"]["id"]) - subject = f"DdS Event {event.title} Registration Invoice {self.invoice_no}" - message = f"Thanks for registering for {event.title}! We look forward to seeing your, in person or virtually.\n\nDépart de Sentier runs its events and schools on a cost-neutral basis - i.e. we don't make a profit off the registration fees. They are used for catering, room, hotel, and equipment rental, AV hosting and technician fees, and guest speaker costs. We literally could not run this event without your support.\n\nYou can view your registration status and apply for membership at https://events.d-d-s.ch/profile.\n\nPlease find attached the registration invoice. Your registration is not finalized until the bank transfer is received.\n\nYou can change your invoice details here: https://events.d-d-s.ch{reverse('event_registration', args=(event.code,))}.\n\nIf you have any questions, please contact events@d-d-s.ch." + event = context["event"] = Event.objects.get(id=self.data["event"]["id"]) + email_template = "dds_registration/payment/emails/invoice_membership.txt.django" + # subject = f"DdS Event {event.title} Registration Invoice {self.invoice_no}" + # message = f"Thanks for registering for {event.title}! We look forward to seeing your, in person or virtually.\n\nDépart de Sentier runs its events and schools on a cost-neutral basis - i.e. we don't make a profit off the registration fees. They are used for catering, room, hotel, and equipment rental, AV hosting and technician fees, and guest speaker costs. We literally could not run this event without your support.\n\nYou can view your registration status and apply for membership at https://events.d-d-s.ch/profile.\n\nPlease find attached the registration invoice. Your registration is not finalized until the bank transfer is received.\n\nYou can change your invoice details here: https://events.d-d-s.ch{reverse('event_registration', args=(event.code,))}.\n\nIf you have any questions, please contact events@d-d-s.ch." + text = render_to_string( + template_name=email_template, + context=context, + request=request, + ) + # Extract a subject and a message from the template + [subject, message] = parse_email_subject_and_content(text) user.email_user( subject=subject, message=message, @@ -302,7 +328,7 @@ def email_invoice(self): attachment_name=f"DdS Invoice {self.invoice_no}.pdf", ) - def email_receipt(self): + def email_receipt(self, request: HttpRequest): user = User.objects.get(id=self.data["user"]["id"]) kind = "Membership" if self.data["kind"] == "membership" else "Event" user.email_user( diff --git a/dds_registration/templates/dds_registration/payment/emails/invoice_event.txt.django b/dds_registration/templates/dds_registration/payment/emails/invoice_event.txt.django new file mode 100644 index 00000000..8be3c2c8 --- /dev/null +++ b/dds_registration/templates/dds_registration/payment/emails/invoice_event.txt.django @@ -0,0 +1,15 @@ +DdS Event {{ event.title }} Registration Invoice {{ payment.invoice_no }} + + +Thanks for registering for {{ event.title }}! We look forward to seeing your, in person or virtually. + +Départ de Sentier runs its events and schools on a cost-neutral basis - i.e. we don't make a profit off the registration fees. They are used for catering, room, hotel, and equipment rental, AV hosting and technician fees, and guest speaker costs. We literally could not run this event without your support. + +You can view your registration status and apply for membership at {{ scheme }}://{{ site.domain }}{% url 'profile' %} + +Please find attached the registration invoice. Your registration is not finalized until the bank transfer is received. + +You can change your invoice details here: {{ scheme }}://{{ site.domain }}{% url 'event_registration' event_code=event.code %}. + +If you have any questions, please contact {{ settings.DEFAULT_CONTACT_EMAIL }}. + diff --git a/dds_registration/templates/dds_registration/payment/emails/invoice_membership.txt.django b/dds_registration/templates/dds_registration/payment/emails/invoice_membership.txt.django new file mode 100644 index 00000000..7d573311 --- /dev/null +++ b/dds_registration/templates/dds_registration/payment/emails/invoice_membership.txt.django @@ -0,0 +1,14 @@ +DdS Membership Invoice {{ payment.invoice_no }} + + +Thanks for signing up for Départ de Sentier membership! + +Membership fees allow us to write awesome open source code, deploy open infrastructure, and run community events without spending all our time fundraising. + +Your membership will run until December 31st, {{ user.membership.until }} (Don't worry, you will get a reminder to renew for another year :). + +Please find attached the membership invoice. Your membership is not in force until the bank transfer is received. + +You can change your invoice details here: {{ scheme }}://{{ site.domain }}{{ % url 'membership_application' % }}. + +If you have any questions, please contact {{ settings.DEFAULT_CONTACT_EMAIL }}. diff --git a/dds_registration/views/event_registration.py b/dds_registration/views/event_registration.py index f7306a75..c83933f2 100644 --- a/dds_registration/views/event_registration.py +++ b/dds_registration/views/event_registration.py @@ -101,7 +101,7 @@ def event_registration(request: HttpRequest, event_code: str): registration.save() if payment.data["method"] == "INVOICE": - payment.email_invoice() + payment.email_invoice(request) payment.status = "ISSUED" payment.save() messages.success( diff --git a/dds_registration/views/membership.py b/dds_registration/views/membership.py index 7b5acde3..8156d8f2 100644 --- a/dds_registration/views/membership.py +++ b/dds_registration/views/membership.py @@ -69,7 +69,7 @@ def membership_application(request: HttpRequest): if payment.data["method"] == "INVOICE": payment.status = "ISSUED" payment.save() - payment.email_invoice() + payment.email_invoice(request) messages.success( request, f"Your membership has been created! An invoice has been sent to {request.user.email} from events@d-d-s.ch. The invoice can also be downloaded from your profile. Please note your membership is not in force until the invoice is paid.", diff --git a/dds_registration/views/payment_stripe.py b/dds_registration/views/payment_stripe.py index eccc3d32..da4bd8af 100644 --- a/dds_registration/views/payment_stripe.py +++ b/dds_registration/views/payment_stripe.py @@ -78,7 +78,7 @@ def payment_stripe_success(request: HttpRequest, payment_id: int): return redirect("profile") payment.data["price"] = payment.data.pop("stripe_charge_in_progress") - payment.mark_paid() + payment.mark_paid(request) if payment.data["kind"] == "membership": messages.success(request, "Awesome, your membership is paid, and you are good to go!") From 078657381d99db6bd9acee629d9eb7669b255d65 Mon Sep 17 00:00:00 2001 From: lilliputten Date: Wed, 10 Apr 2024 18:56:33 +0700 Subject: [PATCH 3/8] Issue #149: Minor changes. --- .../event_payment_receipt_message_body.txt | 2 +- src/assets/shared/variables.scss | 15 ++- static/assets/styles.css | 98 ------------------- static/assets/styles.css.map | 2 +- 4 files changed, 9 insertions(+), 108 deletions(-) diff --git a/dds_registration/templates/dds_registration/event/event_payment_receipt_message_body.txt b/dds_registration/templates/dds_registration/event/event_payment_receipt_message_body.txt index aa5115e1..15b379c2 100644 --- a/dds_registration/templates/dds_registration/event/event_payment_receipt_message_body.txt +++ b/dds_registration/templates/dds_registration/event/event_payment_receipt_message_body.txt @@ -9,7 +9,7 @@ You have registered and already paid for {{ event.title }}! {% endif %}The payment option you have chosen: {% with option=registration.option %}{{ option.item }}{% if option.price %} ({% if option.currency %}{{ option.currency }} {% endif %}{{ option.price }}){% endif %}{% endwith %}. -{% endcomment %}Your invoice is attached, but can also be download anytime at {{ scheme }}://{{site.domain}}{% url 'billing_event_invoice_download' event_code=event.code %}. +{% endcomment %}Your invoice is attached, but can also be download anytime at {{ scheme }}://{{ site.domain }}{% url 'billing_event_invoice_download' event_code=event.code %}. If you have questions or comments, you can reach us at {{ settings.DEFAULT_FROM_EMAIL }}. diff --git a/src/assets/shared/variables.scss b/src/assets/shared/variables.scss index e33f54c9..e4142869 100644 --- a/src/assets/shared/variables.scss +++ b/src/assets/shared/variables.scss @@ -14,14 +14,13 @@ $defaultFontFamily: 'Roboto', 'Helvetica', 'Arial', sans-serif; // Breakpoints:... -/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`: - * - xs: 0 - * - sm: 576px - * - md: 768px - * - lg: 992px - * - xl: 1200px - * - xxl: 1400px - */ +// Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`: +// - xs: 0 +// - sm: 576px +// - md: 768px +// - lg: 992px +// - xl: 1200px +// - xxl: 1400px $screenXsMin: map.get($grid-breakpoints, 'xs'); // 0 $screenSmMin: map.get($grid-breakpoints, 'sm'); // 576px diff --git a/static/assets/styles.css b/static/assets/styles.css index 4e3be941..db883082 100644 --- a/static/assets/styles.css +++ b/static/assets/styles.css @@ -6,14 +6,6 @@ * @module common.scss * @changed 2024.03.08, 12:00 */ -/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`: - * - xs: 0 - * - sm: 576px - * - md: 768px - * - lg: 992px - * - xl: 1200px - * - xxl: 1400px - */ .item-label, .dimmed-info { opacity: 0.5; @@ -36,14 +28,6 @@ * @module forms.scss * @changed 2024.03.08, 12:00 */ -/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`: - * - xs: 0 - * - sm: 576px - * - md: 768px - * - lg: 992px - * - xl: 1200px - * - xxl: 1400px - */ .asteriskField { display: inline-block; margin-left: 4px; @@ -54,48 +38,14 @@ * @module customize.scss * @changed 2024.03.11, 13:52 */ -/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`: - * - xs: 0 - * - sm: 576px - * - md: 768px - * - lg: 992px - * - xl: 1200px - * - xxl: 1400px - */ :root { --bs-body-font-family: Roboto, Helvetica, Arial, sans-serif; } -/** - * @module fix-django-forms.scss - * @changed 2024.04.08, 19:37 - */ -/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`: - * - xs: 0 - * - sm: 576px - * - md: 768px - * - lg: 992px - * - xl: 1200px - * - xxl: 1400px - */ -#div_id_payment_method .form-check { - display: inline-block; - margin-right: 16px; - float: left; -} - /** * @module body * @changed 2024.03.08, 13:30 */ -/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`: - * - xs: 0 - * - sm: 576px - * - md: 768px - * - lg: 992px - * - xl: 1200px - * - xxl: 1400px - */ body { font-family: "Roboto", "Helvetica", "Arial", sans-serif; background-color: #fff; @@ -111,14 +61,6 @@ body { * @module bootstrap-theme-fixes * @changed 2024.04.02, 16:21 */ -/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`: - * - xs: 0 - * - sm: 576px - * - md: 768px - * - lg: 992px - * - xl: 1200px - * - xxl: 1400px - */ :root { --bs-primary-rgb: 68, 136, 102; --bs-link-color-rgb: var(--bs-primary-rgb); @@ -215,14 +157,6 @@ body { * @module page-header-navbar.scss * @changed 2024.03.08, 12:00 */ -/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`: - * - xs: 0 - * - sm: 576px - * - md: 768px - * - lg: 992px - * - xl: 1200px - * - xxl: 1400px - */ .page-header-navbar { padding: 0; } @@ -338,14 +272,6 @@ body { * @module main-page-splash * @changed 2024.03.08, 17:06 */ -/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`: - * - xs: 0 - * - sm: 576px - * - md: 768px - * - lg: 992px - * - xl: 1200px - * - xxl: 1400px - */ .main-page-splash { background-color: #375; color: #fff; @@ -379,14 +305,6 @@ body { * @module membership-splash * @changed 2024.03.08, 17:06 */ -/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`: - * - xs: 0 - * - sm: 576px - * - md: 768px - * - lg: 992px - * - xl: 1200px - * - xxl: 1400px - */ .membership-splash { overflow: hidden; position: relative; @@ -498,14 +416,6 @@ body { * @module events-list-table.scss * @changed 2024.03.21, 16:50 */ -/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`: - * - xs: 0 - * - sm: 576px - * - md: 768px - * - lg: 992px - * - xl: 1200px - * - xxl: 1400px - */ .events-list-table { /* .col-registration @@ -544,14 +454,6 @@ body { * @module events-list.scss * @changed 2024.03.18, 00:57 */ -/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`: - * - xs: 0 - * - sm: 576px - * - md: 768px - * - lg: 992px - * - xl: 1200px - * - xxl: 1400px - */ .events-list-block { display: flex; flex-direction: column; diff --git a/static/assets/styles.css.map b/static/assets/styles.css.map index da8ce3af..c99a7d9c 100644 --- a/static/assets/styles.css.map +++ b/static/assets/styles.css.map @@ -1 +1 @@ -{"version":3,"sources":["styles.scss","common/common.scss","shared/variables.scss","styles.css","common/forms.scss","common/customize.scss","body/body.scss","forms/data-form.scss","theme/bootstrap-theme-fixes.scss","page-header-navbar/page-header-navbar.scss","shared/mixins.scss","page-footer-navbar/page-footer-navbar.scss","main-page-splash/main-page-splash.scss","membership-splash/membership-splash.scss","events-list-table/events-list-table.scss","events-list-block/events-list-block.scss"],"names":[],"mappings":"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","file":"styles.css","sourcesContent":["/**\n * @module styles.scss\n * @changed 2024.04.08, 19:38\n */\n\n@import 'common/common';\n@import 'common/forms';\n@import 'common/customize';\n\n@import 'common/fix-django-forms';\n\n// @import 'test/test'; // DEBUG\n\n@import 'body/body';\n@import 'forms/data-form';\n\n@import 'theme/bootstrap-theme-fixes';\n\n@import 'page-header-navbar/page-header-navbar';\n@import 'page-footer-navbar/page-footer-navbar';\n\n@import 'main-page-splash/main-page-splash';\n@import 'membership-splash/membership-splash';\n\n@import 'events-list-table/events-list-table';\n@import 'events-list-block/events-list-block';\n\n// @import 'membership-choose-list/membership-choose-list'; // UNUSED?\n","/**\n * @module common.scss\n * @changed 2024.03.08, 12:00\n */\n\n@import '../shared';\n\n.item-label,\n.dimmed-info {\n opacity: 0.5;\n}\n.primary-color {\n color: $primaryColor;\n}\n.optional-message:empty {\n display: none;\n}\n\n.common-actions {\n a:not(.btn) {\n margin-left: 8px;\n margin-right: 8px;\n }\n}\n","@use 'sass:map';\n@use 'sass:math';\n@use 'sass:color';\n\n@import '../../vendor/bootstrap-5.3.2/scss/functions';\n@import '../../vendor/bootstrap-5.3.2/scss/variables';\n\n// Font...\n\n$defaultFontSize: 14px;\n\n$defaultFontFamily: 'Roboto', 'Helvetica', 'Arial', sans-serif;\n// $defaultFontFamily: Roboto, system-ui, -apple-system, \"Segoe UI\", \"Helvetica Neue\", \"Noto Sans\", \"Liberation Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n\n// Breakpoints:...\n\n/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`:\n * - xs: 0\n * - sm: 576px\n * - md: 768px\n * - lg: 992px\n * - xl: 1200px\n * - xxl: 1400px\n */\n\n$screenXsMin: map.get($grid-breakpoints, 'xs'); // 0\n$screenSmMin: map.get($grid-breakpoints, 'sm'); // 576px\n$screenMdMin: map.get($grid-breakpoints, 'md'); // 768px\n$screenLgMin: map.get($grid-breakpoints, 'lg'); // 992px\n$screenXlMin: map.get($grid-breakpoints, 'xl'); // 1200px\n$screenXxlMin: map.get($grid-breakpoints, 'xxl'); // 1400px\n\n$screenXsMax: map.get($grid-breakpoints, 'sm'); // 576px\n$screenSmMax: map.get($grid-breakpoints, 'md'); // 768px\n$screenMdMax: map.get($grid-breakpoints, 'lg'); // 992px\n$screenLgMax: map.get($grid-breakpoints, 'xl'); // 1200px\n$screenXlMax: map.get($grid-breakpoints, 'xxl'); // 1400px\n\n// Collapsable widths...\n\n$collapseWidth: screenMdMin; // $grid-float-breakpoint; // =@screen-sm-min=768px ? =@screen-md-min=992px\n$navbarCollapse: $screenLgMin;\n$navbarCollapseMax: $screenMdMax;\n$midbarCollapse: $collapseWidth;\n\n// Primary color...\n\n$primaryLightColor: #8a9;\n$primaryColor: #486;\n$primaryDarkColor: #375;\n$primaryDarkenColor: color.adjust($primaryDarkColor, $lightness: -10%);\n$primaryDarkestColor: #3c5343;\n\n$primaryColorRgb: 68, 136, 102;\n\n// Misc colors...\n\n// UNUSED?\n$xdarkBlueColor: #036;\n$darkBlueColor: #047;\n$mediumBlueColor: #157;\n$moodBlueColor: #6ac;\n$extralightBlueColor: #def;\n\n$darkGreenColor: #461;\n$mediumGreenColor: #9a0;\n\n$defaultTextColor: #333;\n\n$backgroundColor: #fff;\n\n// Navbar...\n\n$navbarMainHeight: 60px;\n$navbarPlusHeight: 50px;\n\n// Timeouts...\n\n$momentTime: 150ms;\n$transitionTime: 250ms;\n$animationTime: 500ms;\n$effectTime: 1000ms;\n","/**\n * @module styles.scss\n * @changed 2024.04.08, 19:38\n */\n/**\n * @module common.scss\n * @changed 2024.03.08, 12:00\n */\n/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`:\n * - xs: 0\n * - sm: 576px\n * - md: 768px\n * - lg: 992px\n * - xl: 1200px\n * - xxl: 1400px\n */\n.item-label,\n.dimmed-info {\n opacity: 0.5;\n}\n\n.primary-color {\n color: #486;\n}\n\n.optional-message:empty {\n display: none;\n}\n\n.common-actions a:not(.btn) {\n margin-left: 8px;\n margin-right: 8px;\n}\n\n/**\n * @module forms.scss\n * @changed 2024.03.08, 12:00\n */\n/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`:\n * - xs: 0\n * - sm: 576px\n * - md: 768px\n * - lg: 992px\n * - xl: 1200px\n * - xxl: 1400px\n */\n.asteriskField {\n display: inline-block;\n margin-left: 4px;\n opacity: 0.5;\n}\n\n/**\n * @module customize.scss\n * @changed 2024.03.11, 13:52\n */\n/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`:\n * - xs: 0\n * - sm: 576px\n * - md: 768px\n * - lg: 992px\n * - xl: 1200px\n * - xxl: 1400px\n */\n:root {\n --bs-body-font-family: Roboto, Helvetica, Arial, sans-serif;\n}\n\n/**\n * @module fix-django-forms.scss\n * @changed 2024.04.08, 19:37\n */\n/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`:\n * - xs: 0\n * - sm: 576px\n * - md: 768px\n * - lg: 992px\n * - xl: 1200px\n * - xxl: 1400px\n */\n#div_id_payment_method .form-check {\n display: inline-block;\n margin-right: 16px;\n float: left;\n}\n\n/**\n * @module body\n * @changed 2024.03.08, 13:30\n */\n/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`:\n * - xs: 0\n * - sm: 576px\n * - md: 768px\n * - lg: 992px\n * - xl: 1200px\n * - xxl: 1400px\n */\nbody {\n font-family: \"Roboto\", \"Helvetica\", \"Arial\", sans-serif;\n background-color: #fff;\n margin-top: 80px;\n}\n\n.data-form .form-group {\n margin-top: 8px;\n margin-bottom: 8px;\n}\n\n/**\n * @module bootstrap-theme-fixes\n * @changed 2024.04.02, 16:21\n */\n/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`:\n * - xs: 0\n * - sm: 576px\n * - md: 768px\n * - lg: 992px\n * - xl: 1200px\n * - xxl: 1400px\n */\n:root {\n --bs-primary-rgb: 68, 136, 102;\n --bs-link-color-rgb: var(--bs-primary-rgb);\n --bs-link-color: #486;\n --bs-link-hover-color: #24533c;\n --bs-link-hover-color-rgb: var(--bs-link-hover-color);\n}\n\n.btn-primary {\n --bs-btn-bg: #486;\n --bs-btn-border-color: #486;\n --bs-btn-hover-bg: #375;\n --bs-btn-hover-border-color: #24533c;\n --bs-btn-focus-shadow-rgb: #8a9;\n --bs-btn-active-bg: #24533c;\n --bs-btn-active-border-color: #24533c;\n --bs-btn-disabled-bg: #486;\n --bs-btn-disabled-border-color: #486;\n}\n\n.btn-outline-primary {\n --bs-btn-color: #486;\n --bs-btn-border-color: #486;\n --bs-btn-hover-bg: #486;\n --bs-btn-hover-border-color: #486;\n --bs-btn-focus-shadow-rgb: #486;\n --bs-btn-active-bg: #486;\n --bs-btn-active-border-color: #486;\n --bs-btn-disabled-color: #486;\n --bs-btn-disabled-border-color: #486;\n}\n\n.btn-outline-primary.btn-link {\n text-decoration: none;\n}\n.btn-outline-primary.btn-link:active, .btn-outline-primary.btn-link:hover {\n color: #fff;\n}\n\n.progress,\n.progress-stacked {\n --bs-progress-bar-bg: #486;\n}\n\n.list-group {\n --bs-list-group-active-bg: #486;\n --bs-list-group-active-border-color: #486;\n}\n\n.btn:focus-visible,\n.btn-check:checked + .btn:focus-visible,\n:not(.btn-check) + .btn:active:focus-visible,\n.btn:first-child:active:focus-visible,\n.btn.active:focus-visible,\n.btn.show:focus-visible,\n.form-check-input:focus,\n.form-select:focus,\n.form-control:focus {\n box-shadow: 0 0 0 0.25rem rgba(136, 170, 153, 0.25);\n border-color: #8a9;\n}\n\n.form-check-input:checked {\n background-color: #486;\n border-color: #486;\n}\n\n.table-primary-header thead th {\n background-color: #486;\n color: #fff;\n}\n.table-primary-header th,\n.table-primary-header td {\n border-right-width: var(--bs-border-width);\n}\n.table-primary-header th:first-child,\n.table-primary-header td:first-child {\n border-left-width: var(--bs-border-width);\n}\n\n.btn-icon {\n padding-left: 0;\n padding-right: 0;\n width: 38px;\n height: 38px;\n}\n.btn-icon, .btn-icon > i {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n/**\n * @module page-header-navbar.scss\n * @changed 2024.03.08, 12:00\n */\n/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`:\n * - xs: 0\n * - sm: 576px\n * - md: 768px\n * - lg: 992px\n * - xl: 1200px\n * - xxl: 1400px\n */\n.page-header-navbar {\n padding: 0;\n}\n.page-header-navbar .main-bar {\n flex: 1;\n display: flex;\n width: 100%;\n align-items: center;\n}\n.page-header-navbar .navbar-brand {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.page-header-navbar.navbar-dark.navbar-primary {\n background-color: #375;\n color: #fff;\n}\n.page-header-navbar.navbar-dark.navbar-primary:before {\n display: block;\n content: \" \";\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n background-image: url(\"/static/images/splash/curves-bg/curves-x.svg\");\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.page-header-navbar.navbar-dark.navbar-primary .container-fluid {\n z-index: 1;\n}\n.page-header-navbar .dropdown-menu#user-menu {\n right: 0;\n left: auto;\n}\n@media (max-width: 400px) {\n .page-header-navbar .site-name {\n display: none;\n }\n}\n@media (min-width: 992px) {\n .page-header-navbar .navbar-brand {\n flex: 1;\n }\n .page-header-navbar .collapse.navbar-collapse {\n flex: 0;\n }\n}\n.page-header-navbar .nav-link {\n white-space: nowrap;\n color: #fff;\n transition: all 250ms;\n opacity: 0.85;\n}\n.page-header-navbar .nav-link:hover {\n opacity: 1;\n}\n\n/**\n * @module page-footer-navbar\n * @changed 2024.03.08, 13:30\n */\n.page-footer-navbar {\n border-top: 1px solid #eee;\n font-size: 90%;\n margin-bottom: 0;\n margin-top: 20px;\n padding: 0;\n}\n.page-footer-navbar .container-fluid {\n display: flex;\n flex-direction: column;\n flex-wrap: wrap;\n align-content: center;\n align-items: center;\n justify-content: space-between;\n}\n.page-footer-navbar .container-fluid .navbar-right {\n display: flex;\n flex-wrap: wrap;\n}\n@media (min-width: 576px) {\n .page-footer-navbar .container-fluid {\n flex-direction: row;\n }\n .page-footer-navbar .container-fluid .navbar-copyright,\n .page-footer-navbar .container-fluid .navbar-middle,\n .page-footer-navbar .container-fluid .navbar-right {\n flex: 1;\n }\n .page-footer-navbar .container-fluid .navbar-right {\n justify-content: flex-end;\n }\n}\n.page-footer-navbar .navbar-copyright {\n display: flex;\n align-items: center;\n}\n.page-footer-navbar .navbar-nav {\n margin: 0;\n flex-direction: row;\n}\n.page-footer-navbar .navbar-nav .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n}\n\n/**\n * @module main-page-splash\n * @changed 2024.03.08, 17:06\n */\n/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`:\n * - xs: 0\n * - sm: 576px\n * - md: 768px\n * - lg: 992px\n * - xl: 1200px\n * - xxl: 1400px\n */\n.main-page-splash {\n background-color: #375;\n color: #fff;\n position: relative;\n}\n.main-page-splash:before {\n display: block;\n content: \" \";\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n background-image: url(\"/static/images/splash/curves-bg/curves-x.svg\");\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.main-page-splash .container-fluid {\n z-index: 1;\n}\n.main-page-splash > .content {\n position: relative;\n}\n.main-page-splash > .content h1 {\n font-weight: 400;\n}\n\n/**\n * @module membership-splash\n * @changed 2024.03.08, 17:06\n */\n/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`:\n * - xs: 0\n * - sm: 576px\n * - md: 768px\n * - lg: 992px\n * - xl: 1200px\n * - xxl: 1400px\n */\n.membership-splash {\n overflow: hidden;\n position: relative;\n padding: 12px;\n}\n.membership-splash.dark {\n background-color: #375;\n color: #fff;\n}\n.membership-splash.dark:before {\n display: block;\n content: \" \";\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n background-image: url(\"/static/images/splash/curves-bg/curves-x.svg\");\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.membership-splash.dark .container-fluid {\n z-index: 1;\n}\n.membership-splash.light {\n background-color: rgba(136, 170, 153, 0.1);\n}\n.membership-splash.light:before {\n display: block;\n content: \" \";\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n background-image: url(\"/static/images/splash/curves-bg/curves-x.svg\");\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.membership-splash.light .container-fluid {\n z-index: 1;\n}\n.membership-splash > .content {\n position: relative;\n}\n.membership-splash .content-cell {\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 2;\n}\n.membership-splash .content-block {\n padding-top: 1em;\n}\n.membership-splash .content-block h1 {\n font-weight: 300;\n}\n@media (min-width: 768px) {\n .membership-splash .content-block {\n font-size: 120%;\n }\n .membership-splash .content-block h1 {\n font-size: 180%;\n }\n}\n@media (min-width: 992px) {\n .membership-splash .content-block {\n font-size: 140%;\n }\n .membership-splash .content-block h1 {\n font-size: 200%;\n }\n}\n.membership-splash.membership-splash-default .content-block {\n max-width: 480px;\n}\n.membership-splash.membership-splash-user .content-block {\n max-width: 720px;\n}\n.membership-splash .visual-cell {\n background-image: url(\"/static/images/splash/membership/dds-painting.png\");\n background-position: center;\n background-repeat: no-repeat;\n background-size: contain;\n min-height: 320px;\n align-self: flex-start;\n}\n@media (max-width: 992px) {\n .membership-splash .visual-cell {\n display: none;\n }\n}\n.membership-splash a:not(.btn) {\n color: #fff;\n transition: all 250ms;\n text-decoration-thickness: 2px;\n text-decoration-line: underline;\n opacity: 0.8;\n}\n.membership-splash a:not(.btn):hover {\n opacity: 1;\n}\n\n/**\n * @module events-list-table.scss\n * @changed 2024.03.21, 16:50\n */\n/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`:\n * - xs: 0\n * - sm: 576px\n * - md: 768px\n * - lg: 992px\n * - xl: 1200px\n * - xxl: 1400px\n */\n.events-list-table {\n /*\n .col-registration\n .col-event\n .col-participants\n .col-opens\n .col-closes\n .col-payment\n .col-options\n .col-paid\n .col-actions\n */\n}\n.events-list-table .col-actions,\n.events-list-table .col-payment,\n.events-list-table .col-registration,\n.events-list-table .col-participants,\n.events-list-table .col-paid {\n text-align: center;\n}\n.events-list-table tbody th,\n.events-list-table tbody td {\n vertical-align: middle;\n}\n.events-list-table tbody .col-event {\n color: #486;\n}\n.events-list-table tbody .col-actions-wrapper {\n display: flex;\n gap: 4px;\n justify-content: center;\n flex-wrap: wrap;\n}\n\n/**\n * @module events-list.scss\n * @changed 2024.03.18, 00:57\n */\n/* Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`:\n * - xs: 0\n * - sm: 576px\n * - md: 768px\n * - lg: 992px\n * - xl: 1200px\n * - xxl: 1400px\n */\n.events-list-block {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.events-list-block .events-list-item {\n padding: 16px;\n border-radius: 8px;\n}\n.events-list-block .events-list-item.has-registration {\n background-color: rgba(136, 170, 153, 0.25);\n}\n.events-list-block .events-list-item > * {\n margin-bottom: 0.5rem;\n}\n.events-list-block .events-list-item-title {\n color: #486;\n font-weight: 400;\n}\n.events-list-block .events-list-item-details {\n display: flex;\n flex-wrap: wrap;\n gap: 0.1rem 1rem;\n}","/**\n * @module forms.scss\n * @changed 2024.03.08, 12:00\n */\n\n@import '../shared';\n\n.asteriskField {\n // crispy_forms element\n display: inline-block;\n margin-left: 4px;\n opacity: 0.5;\n}\n","/**\n * @module customize.scss\n * @changed 2024.03.11, 13:52\n */\n\n@import '../shared';\n\n:root {\n // --bs-body-font-size: #{$defaultFontSize};\n --bs-body-font-family: #{$defaultFontFamily};\n}\n","/**\n * @module fix-django-forms.scss\n * @changed 2024.04.08, 19:37\n */\n\n@import '../shared';\n\n#div_id_payment_method {\n .form-check {\n // NOTE: Issue #113:\n // Show this radio-group options inline.\n // It's impossible to stylize it using class attribute in\n // `dds_registration/forms.py`. These attrs going to the hidden inner\n // `input`, not to the wrapper, like that:\n // ```\n // \n // ```\n display: inline-block;\n margin-right: 16px;\n float: left;\n }\n}\n","/**\n * @module body\n * @changed 2024.03.08, 13:30\n */\n\n@import '../shared';\n\n$headerNavbarHeight: 60px;\n\nbody {\n font-family: $defaultFontFamily;\n background-color: $backgroundColor;\n // Add space for fixed navar (see `static/assets/page-header-navbar/page-header-navbar.django`)\n margin-top: $headerNavbarHeight + 20px;\n}\n",".data-form {\n .form-group {\n margin-top: 8px;\n margin-bottom: 8px;\n }\n}\n","/**\n * @module bootstrap-theme-fixes\n * @changed 2024.04.02, 16:21\n */\n\n@use 'sass:color';\n\n@import '../shared';\n\n:root {\n --bs-primary-rgb: #{$primaryColorRgb};\n --bs-link-color-rgb: var(--bs-primary-rgb);\n --bs-link-color: #{$primaryColor}; // #0d6efd;\n // --bs-link-color-rgb: 13, 110, 253;\n // --bs-link-decoration: underline;\n --bs-link-hover-color: #{$primaryDarkenColor}; // #0a58ca;\n --bs-link-hover-color-rgb: var(--bs-link-hover-color);\n // --bs-link-hover-color-rgb: 10, 88, 202;\n // --bs-border-color: #{$primaryColor};\n}\n\n.btn-primary {\n // --bs-btn-color: #fff;\n --bs-btn-bg: #{$primaryColor}; // #0d6efd;\n --bs-btn-border-color: #{$primaryColor}; // #0d6efd;\n // --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #{$primaryDarkColor}; // #0b5ed7;\n --bs-btn-hover-border-color: #{$primaryDarkenColor}; // #0a58ca;\n --bs-btn-focus-shadow-rgb: #{$primaryLightColor}; // #3184fd; // 49, 132, 253;\n // --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #{$primaryDarkenColor}; // #0a58ca;\n --bs-btn-active-border-color: #{$primaryDarkenColor}; // #0a53be;\n // --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n // --bs-btn-disabled-color: #fff;\n --bs-btn-disabled-bg: #{$primaryColor}; // #0d6efd;\n --bs-btn-disabled-border-color: #{$primaryColor}; // #0d6efd;\n}\n\n.btn-outline-primary {\n --bs-btn-color: #{$primaryColor}; // #0d6efd\n --bs-btn-border-color: #{$primaryColor}; // #0d6efd\n // --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #{$primaryColor}; // #0d6efd\n --bs-btn-hover-border-color: #{$primaryColor}; // #0d6efd\n --bs-btn-focus-shadow-rgb: #{$primaryColor}; // #0d6efd\n // --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #{$primaryColor}; // #0d6efd\n --bs-btn-active-border-color: #{$primaryColor}; // #0d6efd\n // --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #{$primaryColor}; // #0d6efd\n // --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #{$primaryColor}; // #0d6efd\n // --bs-gradient: none;\n}\n\n// Fix hover styles for combined primary outlined and link buttons\n.btn-outline-primary.btn-link {\n &:active,\n &:hover {\n color: #fff;\n }\n text-decoration: none;\n}\n\n.progress,\n.progress-stacked {\n // --bs-progress-height: 1rem;\n // --bs-progress-font-size: 0.75rem;\n // --bs-progress-bg: var(--bs-secondary-bg);\n // --bs-progress-border-radius: var(--bs-border-radius);\n // --bs-progress-box-shadow: var(--bs-box-shadow-inset);\n // --bs-progress-bar-color: #fff;\n --bs-progress-bar-bg: #{$primaryColor}; // #0d6efd;\n // --bs-progress-bar-transition: width 0.6s ease;\n}\n\n.list-group {\n // --bs-list-group-color: var(--bs-body-color);\n // --bs-list-group-bg: var(--bs-body-bg);\n // --bs-list-group-border-color: var(--bs-border-color);\n // --bs-list-group-border-width: var(--bs-border-width);\n // --bs-list-group-border-radius: var(--bs-border-radius);\n // --bs-list-group-item-padding-x: 1rem;\n // --bs-list-group-item-padding-y: 0.5rem;\n // --bs-list-group-action-color: var(--bs-secondary-color);\n // --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n // --bs-list-group-action-hover-bg: var(--bs-tertiary-bg);\n // --bs-list-group-action-active-color: var(--bs-body-color);\n // --bs-list-group-action-active-bg: var(--bs-secondary-bg);\n // --bs-list-group-disabled-color: var(--bs-secondary-color);\n // --bs-list-group-disabled-bg: var(--bs-body-bg);\n // --bs-list-group-active-color: #fff;\n --bs-list-group-active-bg: #{$primaryColor}; // #0d6efd;\n --bs-list-group-active-border-color: #{$primaryColor}; // #0d6efd;\n}\n\n.btn:focus-visible,\n.btn-check:checked + .btn:focus-visible,\n:not(.btn-check) + .btn:active:focus-visible,\n.btn:first-child:active:focus-visible,\n.btn.active:focus-visible,\n.btn.show:focus-visible,\n.form-check-input:focus,\n.form-select:focus,\n.form-control:focus {\n box-shadow: 0 0 0 0.25rem color.change($primaryLightColor, $alpha: 0.25);\n border-color: $primaryLightColor;\n}\n\n.form-check-input:checked {\n background-color: $primaryColor;\n border-color: $primaryColor;\n}\n\n.table-primary-header {\n thead th {\n background-color: $primaryColor;\n color: #fff;\n }\n th,\n td {\n border-right-width: var(--bs-border-width);\n &:first-child {\n border-left-width: var(--bs-border-width);\n }\n }\n}\n\n.btn-icon {\n padding-left: 0;\n padding-right: 0;\n // For md size:\n width: 38px;\n height: 38px;\n &,\n & > i {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n }\n}\n","/**\n * @module page-header-navbar.scss\n * @changed 2024.03.08, 12:00\n */\n\n@import '../shared';\n\n.page-header-navbar {\n padding: 0;\n // Adaptive layout: trim too long title string with an ellipsis...\n .main-bar {\n flex: 1;\n display: flex;\n width: 100%;\n align-items: center;\n }\n .navbar-brand {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n // Dark primary navbar with background decor...\n &.navbar-dark.navbar-primary {\n @include themeBackgroundBefore;\n }\n .dropdown-menu#user-menu {\n // Position dropdown popup relative to the right screen side (as the menu is positioned to the right)\n right: 0;\n left: auto;\n }\n @media (max-width: 400px) {\n .site-name {\n display: none;\n }\n }\n @media (min-width: $navbarCollapse) {\n .navbar-brand {\n flex: 1;\n }\n .collapse.navbar-collapse {\n flex: 0;\n }\n }\n .nav-link {\n white-space: nowrap;\n color: #fff;\n transition: all $transitionTime;\n opacity: 0.85;\n &:hover {\n opacity: 1;\n }\n }\n}\n","@mixin themeBackground {\n background-image: url('/static/images/splash/curves-bg/curves-x.svg');\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n@mixin themeBackgroundBaseBefore {\n &:before {\n display: block;\n content: ' ';\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n @include themeBackground;\n }\n .container-fluid {\n z-index: 1;\n }\n}\n@mixin themeBackgroundBefore {\n background-color: $primaryDarkColor;\n color: #fff;\n @include themeBackgroundBaseBefore;\n}\n","/**\n * @module page-footer-navbar\n * @changed 2024.03.08, 13:30\n */\n\n.page-footer-navbar {\n $borderColor: #eee;\n border-top: 1px solid $borderColor;\n font-size: 90%;\n // border-bottom: 1px solid $borderColor;\n margin-bottom: 0;\n margin-top: 20px;\n padding: 0;\n .container-fluid {\n display: flex;\n flex-direction: column;\n flex-wrap: wrap;\n align-content: center;\n align-items: center;\n justify-content: space-between;\n .navbar-right {\n display: flex;\n flex-wrap: wrap;\n }\n @media (min-width: $screenSmMin) {\n flex-direction: row;\n .navbar-copyright,\n .navbar-middle,\n .navbar-right {\n flex: 1;\n }\n .navbar-copyright {\n }\n .navbar-middle {\n }\n .navbar-right {\n justify-content: flex-end;\n }\n }\n }\n .navbar-copyright {\n display: flex;\n align-items: center;\n // gap: 10px;\n }\n .navbar-nav {\n margin: 0;\n flex-direction: row;\n .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n }\n }\n}\n","/**\n * @module main-page-splash\n * @changed 2024.03.08, 17:06\n */\n\n@import '../shared';\n\n.main-page-splash {\n @include themeBackgroundBefore;\n position: relative;\n > .content {\n h1 {\n font-weight: 400;\n }\n position: relative;\n }\n}\n","/**\n * @module membership-splash\n * @changed 2024.03.08, 17:06\n */\n\n@use 'sass:color';\n\n@import '../shared';\n\n.membership-splash {\n overflow: hidden;\n position: relative;\n padding: 12px;\n // Theming...\n &.dark {\n @include themeBackgroundBefore;\n }\n &.light {\n background-color: color.change($primaryLightColor, $alpha: 0.1);\n @include themeBackgroundBaseBefore;\n }\n // Ensure z-index for content...\n > .content {\n position: relative;\n }\n .content-cell {\n // text-align: center;\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 2;\n }\n .content-block {\n padding-top: 1em;\n h1 {\n font-weight: 300;\n }\n @media (min-width: $screenMdMin) {\n font-size: 120%;\n h1 {\n font-size: 180%;\n }\n }\n @media (min-width: $screenLgMin) {\n font-size: 140%;\n h1 {\n font-size: 200%;\n }\n }\n }\n &.membership-splash-default .content-block {\n max-width: 480px;\n }\n &.membership-splash-user .content-block {\n max-width: 720px;\n }\n .visual-cell {\n @media (max-width: $screenMdMax) {\n // Hide on small screens\n display: none;\n }\n background-image: url('/static/images/splash/membership/dds-painting.png');\n background-position: center;\n background-repeat: no-repeat;\n background-size: contain;\n min-height: 320px;\n align-self: flex-start;\n }\n a:not(.btn) {\n color: #fff;\n transition: all $transitionTime;\n text-decoration-thickness: 2px;\n text-decoration-line: underline;\n opacity: 0.8;\n &:hover {\n opacity: 1;\n }\n }\n}\n","/**\n * @module events-list-table.scss\n * @changed 2024.03.21, 16:50\n */\n\n@import '../shared';\n\n.events-list-table {\n /*\n .col-registration\n .col-event\n .col-participants\n .col-opens\n .col-closes\n .col-payment\n .col-options\n .col-paid\n .col-actions\n */\n\n .col-actions,\n .col-payment,\n .col-registration,\n .col-participants,\n .col-paid {\n text-align: center;\n }\n\n tbody {\n th,\n td {\n vertical-align: middle;\n }\n .col-event {\n color: $primaryColor;\n }\n .col-actions-wrapper {\n display: flex;\n gap: 4px;\n justify-content: center;\n flex-wrap: wrap;\n }\n }\n}\n","/**\n * @module events-list.scss\n * @changed 2024.03.18, 00:57\n */\n\n@use 'sass:color';\n\n@import '../shared';\n\n.events-list-block {\n display: flex;\n flex-direction: column;\n gap: 8px;\n .events-list-item {\n padding: 16px;\n border-radius: 8px;\n &.has-registration {\n background-color: color.change($primaryLightColor, $alpha: 0.25);\n }\n & > * {\n margin-bottom: 0.5rem;\n }\n }\n .events-list-item-title {\n color: $primaryColor;\n font-weight: 400;\n }\n .events-list-item-details {\n display: flex;\n flex-wrap: wrap;\n gap: 0.1rem 1rem;\n }\n}\n"]} +{"version":3,"sources":["styles.scss","common/common.scss","styles.css","shared/variables.scss","common/forms.scss","common/customize.scss","body/body.scss","forms/data-form.scss","theme/bootstrap-theme-fixes.scss","page-header-navbar/page-header-navbar.scss","shared/mixins.scss","page-footer-navbar/page-footer-navbar.scss","main-page-splash/main-page-splash.scss","membership-splash/membership-splash.scss","events-list-table/events-list-table.scss","events-list-block/events-list-block.scss"],"names":[],"mappings":"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","file":"styles.css","sourcesContent":["/**\n * @module styles.scss\n * @changed 2024.04.08, 19:38\n */\n\n@import 'common/common';\n@import 'common/forms';\n@import 'common/customize';\n\n// @import 'test/test'; // DEBUG\n\n@import 'body/body';\n@import 'forms/data-form';\n\n@import 'theme/bootstrap-theme-fixes';\n\n@import 'page-header-navbar/page-header-navbar';\n@import 'page-footer-navbar/page-footer-navbar';\n\n@import 'main-page-splash/main-page-splash';\n@import 'membership-splash/membership-splash';\n\n@import 'events-list-table/events-list-table';\n@import 'events-list-block/events-list-block';\n\n// @import 'membership-choose-list/membership-choose-list'; // UNUSED?\n","/**\n * @module common.scss\n * @changed 2024.03.08, 12:00\n */\n\n@import '../shared';\n\n.item-label,\n.dimmed-info {\n opacity: 0.5;\n}\n.primary-color {\n color: $primaryColor;\n}\n.optional-message:empty {\n display: none;\n}\n\n.common-actions {\n a:not(.btn) {\n margin-left: 8px;\n margin-right: 8px;\n }\n}\n","/**\n * @module styles.scss\n * @changed 2024.04.08, 19:38\n */\n/**\n * @module common.scss\n * @changed 2024.03.08, 12:00\n */\n.item-label,\n.dimmed-info {\n opacity: 0.5;\n}\n\n.primary-color {\n color: #486;\n}\n\n.optional-message:empty {\n display: none;\n}\n\n.common-actions a:not(.btn) {\n margin-left: 8px;\n margin-right: 8px;\n}\n\n/**\n * @module forms.scss\n * @changed 2024.03.08, 12:00\n */\n.asteriskField {\n display: inline-block;\n margin-left: 4px;\n opacity: 0.5;\n}\n\n/**\n * @module customize.scss\n * @changed 2024.03.11, 13:52\n */\n:root {\n --bs-body-font-family: Roboto, Helvetica, Arial, sans-serif;\n}\n\n/**\n * @module body\n * @changed 2024.03.08, 13:30\n */\nbody {\n font-family: \"Roboto\", \"Helvetica\", \"Arial\", sans-serif;\n background-color: #fff;\n margin-top: 80px;\n}\n\n.data-form .form-group {\n margin-top: 8px;\n margin-bottom: 8px;\n}\n\n/**\n * @module bootstrap-theme-fixes\n * @changed 2024.04.02, 16:21\n */\n:root {\n --bs-primary-rgb: 68, 136, 102;\n --bs-link-color-rgb: var(--bs-primary-rgb);\n --bs-link-color: #486;\n --bs-link-hover-color: #24533c;\n --bs-link-hover-color-rgb: var(--bs-link-hover-color);\n}\n\n.btn-primary {\n --bs-btn-bg: #486;\n --bs-btn-border-color: #486;\n --bs-btn-hover-bg: #375;\n --bs-btn-hover-border-color: #24533c;\n --bs-btn-focus-shadow-rgb: #8a9;\n --bs-btn-active-bg: #24533c;\n --bs-btn-active-border-color: #24533c;\n --bs-btn-disabled-bg: #486;\n --bs-btn-disabled-border-color: #486;\n}\n\n.btn-outline-primary {\n --bs-btn-color: #486;\n --bs-btn-border-color: #486;\n --bs-btn-hover-bg: #486;\n --bs-btn-hover-border-color: #486;\n --bs-btn-focus-shadow-rgb: #486;\n --bs-btn-active-bg: #486;\n --bs-btn-active-border-color: #486;\n --bs-btn-disabled-color: #486;\n --bs-btn-disabled-border-color: #486;\n}\n\n.btn-outline-primary.btn-link {\n text-decoration: none;\n}\n.btn-outline-primary.btn-link:active, .btn-outline-primary.btn-link:hover {\n color: #fff;\n}\n\n.progress,\n.progress-stacked {\n --bs-progress-bar-bg: #486;\n}\n\n.list-group {\n --bs-list-group-active-bg: #486;\n --bs-list-group-active-border-color: #486;\n}\n\n.btn:focus-visible,\n.btn-check:checked + .btn:focus-visible,\n:not(.btn-check) + .btn:active:focus-visible,\n.btn:first-child:active:focus-visible,\n.btn.active:focus-visible,\n.btn.show:focus-visible,\n.form-check-input:focus,\n.form-select:focus,\n.form-control:focus {\n box-shadow: 0 0 0 0.25rem rgba(136, 170, 153, 0.25);\n border-color: #8a9;\n}\n\n.form-check-input:checked {\n background-color: #486;\n border-color: #486;\n}\n\n.table-primary-header thead th {\n background-color: #486;\n color: #fff;\n}\n.table-primary-header th,\n.table-primary-header td {\n border-right-width: var(--bs-border-width);\n}\n.table-primary-header th:first-child,\n.table-primary-header td:first-child {\n border-left-width: var(--bs-border-width);\n}\n\n.btn-icon {\n padding-left: 0;\n padding-right: 0;\n width: 38px;\n height: 38px;\n}\n.btn-icon, .btn-icon > i {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n/**\n * @module page-header-navbar.scss\n * @changed 2024.03.08, 12:00\n */\n.page-header-navbar {\n padding: 0;\n}\n.page-header-navbar .main-bar {\n flex: 1;\n display: flex;\n width: 100%;\n align-items: center;\n}\n.page-header-navbar .navbar-brand {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.page-header-navbar.navbar-dark.navbar-primary {\n background-color: #375;\n color: #fff;\n}\n.page-header-navbar.navbar-dark.navbar-primary:before {\n display: block;\n content: \" \";\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n background-image: url(\"/static/images/splash/curves-bg/curves-x.svg\");\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.page-header-navbar.navbar-dark.navbar-primary .container-fluid {\n z-index: 1;\n}\n.page-header-navbar .dropdown-menu#user-menu {\n right: 0;\n left: auto;\n}\n@media (max-width: 400px) {\n .page-header-navbar .site-name {\n display: none;\n }\n}\n@media (min-width: 992px) {\n .page-header-navbar .navbar-brand {\n flex: 1;\n }\n .page-header-navbar .collapse.navbar-collapse {\n flex: 0;\n }\n}\n.page-header-navbar .nav-link {\n white-space: nowrap;\n color: #fff;\n transition: all 250ms;\n opacity: 0.85;\n}\n.page-header-navbar .nav-link:hover {\n opacity: 1;\n}\n\n/**\n * @module page-footer-navbar\n * @changed 2024.03.08, 13:30\n */\n.page-footer-navbar {\n border-top: 1px solid #eee;\n font-size: 90%;\n margin-bottom: 0;\n margin-top: 20px;\n padding: 0;\n}\n.page-footer-navbar .container-fluid {\n display: flex;\n flex-direction: column;\n flex-wrap: wrap;\n align-content: center;\n align-items: center;\n justify-content: space-between;\n}\n.page-footer-navbar .container-fluid .navbar-right {\n display: flex;\n flex-wrap: wrap;\n}\n@media (min-width: 576px) {\n .page-footer-navbar .container-fluid {\n flex-direction: row;\n }\n .page-footer-navbar .container-fluid .navbar-copyright,\n .page-footer-navbar .container-fluid .navbar-middle,\n .page-footer-navbar .container-fluid .navbar-right {\n flex: 1;\n }\n .page-footer-navbar .container-fluid .navbar-right {\n justify-content: flex-end;\n }\n}\n.page-footer-navbar .navbar-copyright {\n display: flex;\n align-items: center;\n}\n.page-footer-navbar .navbar-nav {\n margin: 0;\n flex-direction: row;\n}\n.page-footer-navbar .navbar-nav .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n}\n\n/**\n * @module main-page-splash\n * @changed 2024.03.08, 17:06\n */\n.main-page-splash {\n background-color: #375;\n color: #fff;\n position: relative;\n}\n.main-page-splash:before {\n display: block;\n content: \" \";\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n background-image: url(\"/static/images/splash/curves-bg/curves-x.svg\");\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.main-page-splash .container-fluid {\n z-index: 1;\n}\n.main-page-splash > .content {\n position: relative;\n}\n.main-page-splash > .content h1 {\n font-weight: 400;\n}\n\n/**\n * @module membership-splash\n * @changed 2024.03.08, 17:06\n */\n.membership-splash {\n overflow: hidden;\n position: relative;\n padding: 12px;\n}\n.membership-splash.dark {\n background-color: #375;\n color: #fff;\n}\n.membership-splash.dark:before {\n display: block;\n content: \" \";\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n background-image: url(\"/static/images/splash/curves-bg/curves-x.svg\");\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.membership-splash.dark .container-fluid {\n z-index: 1;\n}\n.membership-splash.light {\n background-color: rgba(136, 170, 153, 0.1);\n}\n.membership-splash.light:before {\n display: block;\n content: \" \";\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n background-image: url(\"/static/images/splash/curves-bg/curves-x.svg\");\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.membership-splash.light .container-fluid {\n z-index: 1;\n}\n.membership-splash > .content {\n position: relative;\n}\n.membership-splash .content-cell {\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 2;\n}\n.membership-splash .content-block {\n padding-top: 1em;\n}\n.membership-splash .content-block h1 {\n font-weight: 300;\n}\n@media (min-width: 768px) {\n .membership-splash .content-block {\n font-size: 120%;\n }\n .membership-splash .content-block h1 {\n font-size: 180%;\n }\n}\n@media (min-width: 992px) {\n .membership-splash .content-block {\n font-size: 140%;\n }\n .membership-splash .content-block h1 {\n font-size: 200%;\n }\n}\n.membership-splash.membership-splash-default .content-block {\n max-width: 480px;\n}\n.membership-splash.membership-splash-user .content-block {\n max-width: 720px;\n}\n.membership-splash .visual-cell {\n background-image: url(\"/static/images/splash/membership/dds-painting.png\");\n background-position: center;\n background-repeat: no-repeat;\n background-size: contain;\n min-height: 320px;\n align-self: flex-start;\n}\n@media (max-width: 992px) {\n .membership-splash .visual-cell {\n display: none;\n }\n}\n.membership-splash a:not(.btn) {\n color: #fff;\n transition: all 250ms;\n text-decoration-thickness: 2px;\n text-decoration-line: underline;\n opacity: 0.8;\n}\n.membership-splash a:not(.btn):hover {\n opacity: 1;\n}\n\n/**\n * @module events-list-table.scss\n * @changed 2024.03.21, 16:50\n */\n.events-list-table {\n /*\n .col-registration\n .col-event\n .col-participants\n .col-opens\n .col-closes\n .col-payment\n .col-options\n .col-paid\n .col-actions\n */\n}\n.events-list-table .col-actions,\n.events-list-table .col-payment,\n.events-list-table .col-registration,\n.events-list-table .col-participants,\n.events-list-table .col-paid {\n text-align: center;\n}\n.events-list-table tbody th,\n.events-list-table tbody td {\n vertical-align: middle;\n}\n.events-list-table tbody .col-event {\n color: #486;\n}\n.events-list-table tbody .col-actions-wrapper {\n display: flex;\n gap: 4px;\n justify-content: center;\n flex-wrap: wrap;\n}\n\n/**\n * @module events-list.scss\n * @changed 2024.03.18, 00:57\n */\n.events-list-block {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.events-list-block .events-list-item {\n padding: 16px;\n border-radius: 8px;\n}\n.events-list-block .events-list-item.has-registration {\n background-color: rgba(136, 170, 153, 0.25);\n}\n.events-list-block .events-list-item > * {\n margin-bottom: 0.5rem;\n}\n.events-list-block .events-list-item-title {\n color: #486;\n font-weight: 400;\n}\n.events-list-block .events-list-item-details {\n display: flex;\n flex-wrap: wrap;\n gap: 0.1rem 1rem;\n}","@use 'sass:map';\n@use 'sass:math';\n@use 'sass:color';\n\n@import '../../vendor/bootstrap-5.3.2/scss/functions';\n@import '../../vendor/bootstrap-5.3.2/scss/variables';\n\n// Font...\n\n$defaultFontSize: 14px;\n\n$defaultFontFamily: 'Roboto', 'Helvetica', 'Arial', sans-serif;\n// $defaultFontFamily: Roboto, system-ui, -apple-system, \"Segoe UI\", \"Helvetica Neue\", \"Noto Sans\", \"Liberation Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n\n// Breakpoints:...\n\n// Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`:\n// - xs: 0\n// - sm: 576px\n// - md: 768px\n// - lg: 992px\n// - xl: 1200px\n// - xxl: 1400px\n\n$screenXsMin: map.get($grid-breakpoints, 'xs'); // 0\n$screenSmMin: map.get($grid-breakpoints, 'sm'); // 576px\n$screenMdMin: map.get($grid-breakpoints, 'md'); // 768px\n$screenLgMin: map.get($grid-breakpoints, 'lg'); // 992px\n$screenXlMin: map.get($grid-breakpoints, 'xl'); // 1200px\n$screenXxlMin: map.get($grid-breakpoints, 'xxl'); // 1400px\n\n$screenXsMax: map.get($grid-breakpoints, 'sm'); // 576px\n$screenSmMax: map.get($grid-breakpoints, 'md'); // 768px\n$screenMdMax: map.get($grid-breakpoints, 'lg'); // 992px\n$screenLgMax: map.get($grid-breakpoints, 'xl'); // 1200px\n$screenXlMax: map.get($grid-breakpoints, 'xxl'); // 1400px\n\n// Collapsable widths...\n\n$collapseWidth: screenMdMin; // $grid-float-breakpoint; // =@screen-sm-min=768px ? =@screen-md-min=992px\n$navbarCollapse: $screenLgMin;\n$navbarCollapseMax: $screenMdMax;\n$midbarCollapse: $collapseWidth;\n\n// Primary color...\n\n$primaryLightColor: #8a9;\n$primaryColor: #486;\n$primaryDarkColor: #375;\n$primaryDarkenColor: color.adjust($primaryDarkColor, $lightness: -10%);\n$primaryDarkestColor: #3c5343;\n\n$primaryColorRgb: 68, 136, 102;\n\n// Misc colors...\n\n// UNUSED?\n$xdarkBlueColor: #036;\n$darkBlueColor: #047;\n$mediumBlueColor: #157;\n$moodBlueColor: #6ac;\n$extralightBlueColor: #def;\n\n$darkGreenColor: #461;\n$mediumGreenColor: #9a0;\n\n$defaultTextColor: #333;\n\n$backgroundColor: #fff;\n\n// Navbar...\n\n$navbarMainHeight: 60px;\n$navbarPlusHeight: 50px;\n\n// Timeouts...\n\n$momentTime: 150ms;\n$transitionTime: 250ms;\n$animationTime: 500ms;\n$effectTime: 1000ms;\n","/**\n * @module forms.scss\n * @changed 2024.03.08, 12:00\n */\n\n@import '../shared';\n\n.asteriskField {\n // crispy_forms element\n display: inline-block;\n margin-left: 4px;\n opacity: 0.5;\n}\n","/**\n * @module customize.scss\n * @changed 2024.03.11, 13:52\n */\n\n@import '../shared';\n\n:root {\n // --bs-body-font-size: #{$defaultFontSize};\n --bs-body-font-family: #{$defaultFontFamily};\n}\n","/**\n * @module body\n * @changed 2024.03.08, 13:30\n */\n\n@import '../shared';\n\n$headerNavbarHeight: 60px;\n\nbody {\n font-family: $defaultFontFamily;\n background-color: $backgroundColor;\n // Add space for fixed navar (see `static/assets/page-header-navbar/page-header-navbar.django`)\n margin-top: $headerNavbarHeight + 20px;\n}\n",".data-form {\n .form-group {\n margin-top: 8px;\n margin-bottom: 8px;\n }\n}\n","/**\n * @module bootstrap-theme-fixes\n * @changed 2024.04.02, 16:21\n */\n\n@use 'sass:color';\n\n@import '../shared';\n\n:root {\n --bs-primary-rgb: #{$primaryColorRgb};\n --bs-link-color-rgb: var(--bs-primary-rgb);\n --bs-link-color: #{$primaryColor}; // #0d6efd;\n // --bs-link-color-rgb: 13, 110, 253;\n // --bs-link-decoration: underline;\n --bs-link-hover-color: #{$primaryDarkenColor}; // #0a58ca;\n --bs-link-hover-color-rgb: var(--bs-link-hover-color);\n // --bs-link-hover-color-rgb: 10, 88, 202;\n // --bs-border-color: #{$primaryColor};\n}\n\n.btn-primary {\n // --bs-btn-color: #fff;\n --bs-btn-bg: #{$primaryColor}; // #0d6efd;\n --bs-btn-border-color: #{$primaryColor}; // #0d6efd;\n // --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #{$primaryDarkColor}; // #0b5ed7;\n --bs-btn-hover-border-color: #{$primaryDarkenColor}; // #0a58ca;\n --bs-btn-focus-shadow-rgb: #{$primaryLightColor}; // #3184fd; // 49, 132, 253;\n // --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #{$primaryDarkenColor}; // #0a58ca;\n --bs-btn-active-border-color: #{$primaryDarkenColor}; // #0a53be;\n // --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n // --bs-btn-disabled-color: #fff;\n --bs-btn-disabled-bg: #{$primaryColor}; // #0d6efd;\n --bs-btn-disabled-border-color: #{$primaryColor}; // #0d6efd;\n}\n\n.btn-outline-primary {\n --bs-btn-color: #{$primaryColor}; // #0d6efd\n --bs-btn-border-color: #{$primaryColor}; // #0d6efd\n // --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #{$primaryColor}; // #0d6efd\n --bs-btn-hover-border-color: #{$primaryColor}; // #0d6efd\n --bs-btn-focus-shadow-rgb: #{$primaryColor}; // #0d6efd\n // --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #{$primaryColor}; // #0d6efd\n --bs-btn-active-border-color: #{$primaryColor}; // #0d6efd\n // --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #{$primaryColor}; // #0d6efd\n // --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #{$primaryColor}; // #0d6efd\n // --bs-gradient: none;\n}\n\n// Fix hover styles for combined primary outlined and link buttons\n.btn-outline-primary.btn-link {\n &:active,\n &:hover {\n color: #fff;\n }\n text-decoration: none;\n}\n\n.progress,\n.progress-stacked {\n // --bs-progress-height: 1rem;\n // --bs-progress-font-size: 0.75rem;\n // --bs-progress-bg: var(--bs-secondary-bg);\n // --bs-progress-border-radius: var(--bs-border-radius);\n // --bs-progress-box-shadow: var(--bs-box-shadow-inset);\n // --bs-progress-bar-color: #fff;\n --bs-progress-bar-bg: #{$primaryColor}; // #0d6efd;\n // --bs-progress-bar-transition: width 0.6s ease;\n}\n\n.list-group {\n // --bs-list-group-color: var(--bs-body-color);\n // --bs-list-group-bg: var(--bs-body-bg);\n // --bs-list-group-border-color: var(--bs-border-color);\n // --bs-list-group-border-width: var(--bs-border-width);\n // --bs-list-group-border-radius: var(--bs-border-radius);\n // --bs-list-group-item-padding-x: 1rem;\n // --bs-list-group-item-padding-y: 0.5rem;\n // --bs-list-group-action-color: var(--bs-secondary-color);\n // --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n // --bs-list-group-action-hover-bg: var(--bs-tertiary-bg);\n // --bs-list-group-action-active-color: var(--bs-body-color);\n // --bs-list-group-action-active-bg: var(--bs-secondary-bg);\n // --bs-list-group-disabled-color: var(--bs-secondary-color);\n // --bs-list-group-disabled-bg: var(--bs-body-bg);\n // --bs-list-group-active-color: #fff;\n --bs-list-group-active-bg: #{$primaryColor}; // #0d6efd;\n --bs-list-group-active-border-color: #{$primaryColor}; // #0d6efd;\n}\n\n.btn:focus-visible,\n.btn-check:checked + .btn:focus-visible,\n:not(.btn-check) + .btn:active:focus-visible,\n.btn:first-child:active:focus-visible,\n.btn.active:focus-visible,\n.btn.show:focus-visible,\n.form-check-input:focus,\n.form-select:focus,\n.form-control:focus {\n box-shadow: 0 0 0 0.25rem color.change($primaryLightColor, $alpha: 0.25);\n border-color: $primaryLightColor;\n}\n\n.form-check-input:checked {\n background-color: $primaryColor;\n border-color: $primaryColor;\n}\n\n.table-primary-header {\n thead th {\n background-color: $primaryColor;\n color: #fff;\n }\n th,\n td {\n border-right-width: var(--bs-border-width);\n &:first-child {\n border-left-width: var(--bs-border-width);\n }\n }\n}\n\n.btn-icon {\n padding-left: 0;\n padding-right: 0;\n // For md size:\n width: 38px;\n height: 38px;\n &,\n & > i {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n }\n}\n","/**\n * @module page-header-navbar.scss\n * @changed 2024.03.08, 12:00\n */\n\n@import '../shared';\n\n.page-header-navbar {\n padding: 0;\n // Adaptive layout: trim too long title string with an ellipsis...\n .main-bar {\n flex: 1;\n display: flex;\n width: 100%;\n align-items: center;\n }\n .navbar-brand {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n // Dark primary navbar with background decor...\n &.navbar-dark.navbar-primary {\n @include themeBackgroundBefore;\n }\n .dropdown-menu#user-menu {\n // Position dropdown popup relative to the right screen side (as the menu is positioned to the right)\n right: 0;\n left: auto;\n }\n @media (max-width: 400px) {\n .site-name {\n display: none;\n }\n }\n @media (min-width: $navbarCollapse) {\n .navbar-brand {\n flex: 1;\n }\n .collapse.navbar-collapse {\n flex: 0;\n }\n }\n .nav-link {\n white-space: nowrap;\n color: #fff;\n transition: all $transitionTime;\n opacity: 0.85;\n &:hover {\n opacity: 1;\n }\n }\n}\n","@mixin themeBackground {\n background-image: url('/static/images/splash/curves-bg/curves-x.svg');\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n@mixin themeBackgroundBaseBefore {\n &:before {\n display: block;\n content: ' ';\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n @include themeBackground;\n }\n .container-fluid {\n z-index: 1;\n }\n}\n@mixin themeBackgroundBefore {\n background-color: $primaryDarkColor;\n color: #fff;\n @include themeBackgroundBaseBefore;\n}\n","/**\n * @module page-footer-navbar\n * @changed 2024.03.08, 13:30\n */\n\n.page-footer-navbar {\n $borderColor: #eee;\n border-top: 1px solid $borderColor;\n font-size: 90%;\n // border-bottom: 1px solid $borderColor;\n margin-bottom: 0;\n margin-top: 20px;\n padding: 0;\n .container-fluid {\n display: flex;\n flex-direction: column;\n flex-wrap: wrap;\n align-content: center;\n align-items: center;\n justify-content: space-between;\n .navbar-right {\n display: flex;\n flex-wrap: wrap;\n }\n @media (min-width: $screenSmMin) {\n flex-direction: row;\n .navbar-copyright,\n .navbar-middle,\n .navbar-right {\n flex: 1;\n }\n .navbar-copyright {\n }\n .navbar-middle {\n }\n .navbar-right {\n justify-content: flex-end;\n }\n }\n }\n .navbar-copyright {\n display: flex;\n align-items: center;\n // gap: 10px;\n }\n .navbar-nav {\n margin: 0;\n flex-direction: row;\n .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n }\n }\n}\n","/**\n * @module main-page-splash\n * @changed 2024.03.08, 17:06\n */\n\n@import '../shared';\n\n.main-page-splash {\n @include themeBackgroundBefore;\n position: relative;\n > .content {\n h1 {\n font-weight: 400;\n }\n position: relative;\n }\n}\n","/**\n * @module membership-splash\n * @changed 2024.03.08, 17:06\n */\n\n@use 'sass:color';\n\n@import '../shared';\n\n.membership-splash {\n overflow: hidden;\n position: relative;\n padding: 12px;\n // Theming...\n &.dark {\n @include themeBackgroundBefore;\n }\n &.light {\n background-color: color.change($primaryLightColor, $alpha: 0.1);\n @include themeBackgroundBaseBefore;\n }\n // Ensure z-index for content...\n > .content {\n position: relative;\n }\n .content-cell {\n // text-align: center;\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 2;\n }\n .content-block {\n padding-top: 1em;\n h1 {\n font-weight: 300;\n }\n @media (min-width: $screenMdMin) {\n font-size: 120%;\n h1 {\n font-size: 180%;\n }\n }\n @media (min-width: $screenLgMin) {\n font-size: 140%;\n h1 {\n font-size: 200%;\n }\n }\n }\n &.membership-splash-default .content-block {\n max-width: 480px;\n }\n &.membership-splash-user .content-block {\n max-width: 720px;\n }\n .visual-cell {\n @media (max-width: $screenMdMax) {\n // Hide on small screens\n display: none;\n }\n background-image: url('/static/images/splash/membership/dds-painting.png');\n background-position: center;\n background-repeat: no-repeat;\n background-size: contain;\n min-height: 320px;\n align-self: flex-start;\n }\n a:not(.btn) {\n color: #fff;\n transition: all $transitionTime;\n text-decoration-thickness: 2px;\n text-decoration-line: underline;\n opacity: 0.8;\n &:hover {\n opacity: 1;\n }\n }\n}\n","/**\n * @module events-list-table.scss\n * @changed 2024.03.21, 16:50\n */\n\n@import '../shared';\n\n.events-list-table {\n /*\n .col-registration\n .col-event\n .col-participants\n .col-opens\n .col-closes\n .col-payment\n .col-options\n .col-paid\n .col-actions\n */\n\n .col-actions,\n .col-payment,\n .col-registration,\n .col-participants,\n .col-paid {\n text-align: center;\n }\n\n tbody {\n th,\n td {\n vertical-align: middle;\n }\n .col-event {\n color: $primaryColor;\n }\n .col-actions-wrapper {\n display: flex;\n gap: 4px;\n justify-content: center;\n flex-wrap: wrap;\n }\n }\n}\n","/**\n * @module events-list.scss\n * @changed 2024.03.18, 00:57\n */\n\n@use 'sass:color';\n\n@import '../shared';\n\n.events-list-block {\n display: flex;\n flex-direction: column;\n gap: 8px;\n .events-list-item {\n padding: 16px;\n border-radius: 8px;\n &.has-registration {\n background-color: color.change($primaryLightColor, $alpha: 0.25);\n }\n & > * {\n margin-bottom: 0.5rem;\n }\n }\n .events-list-item-title {\n color: $primaryColor;\n font-weight: 400;\n }\n .events-list-item-details {\n display: flex;\n flex-wrap: wrap;\n gap: 0.1rem 1rem;\n }\n}\n"]} \ No newline at end of file From df13fe7d891f61bf7f7be5273ba3ae76705b0492 Mon Sep 17 00:00:00 2001 From: lilliputten Date: Wed, 10 Apr 2024 19:42:32 +0700 Subject: [PATCH 4/8] Issue #149: Fixed error 'Unrecognized currency...' (using currencies list from constants instead of literal list, with missed 'USD' value). --- dds_registration/views/helpers/stripe_amounts.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/dds_registration/views/helpers/stripe_amounts.py b/dds_registration/views/helpers/stripe_amounts.py index caa1e05e..fdf5773f 100644 --- a/dds_registration/views/helpers/stripe_amounts.py +++ b/dds_registration/views/helpers/stripe_amounts.py @@ -1,9 +1,13 @@ +from ...core.constants.payments import site_supported_currencies + + def get_stripe_amount_for_currency(amount: int, currency: str, convert_basic_unit: bool = True) -> int: """Stripe fees vary by country. Note: Assumes amount in stripe basic unit!!!""" if convert_basic_unit: amount = get_stripe_basic_unit(amount=amount, currency=currency) + # NOTE: Must match the list of currencies in `site_supported_currencies` if currency == "USD": # Stripe fee is 2.9%, currency conversion loss is 1% return round(30 + (1 + 0.029 + 0.01) * amount) @@ -24,14 +28,16 @@ def get_stripe_basic_unit(amount: float, currency: str) -> int: """Stripe wants numbers in lower divisible unit. This varies by country.""" - if currency in ("CAD", "CHF", "EUR", "CAD"): + currency_ids = dict(site_supported_currencies).keys() + if currency in currency_ids: return round(amount * 100) else: raise ValueError(f"Unrecognized currency {currency}") def convert_from_stripe_units(amount: float, currency: str) -> float: - if currency in ("CAD", "CHF", "EUR", "CAD"): + currency_ids = dict(site_supported_currencies).keys() + if currency in currency_ids: return round(amount / 100, 2) else: raise ValueError(f"Unrecognized currency {currency}") From 8771cced4e9b17aab4142341ab16210e7213ca6a Mon Sep 17 00:00:00 2001 From: lilliputten Date: Wed, 10 Apr 2024 19:44:58 +0700 Subject: [PATCH 5/8] Issue #149: Removed 'test' assets. --- src/assets/styles.scss | 2 -- src/assets/test/test.django | 22 ---------------------- src/assets/test/test.scss | 13 ------------- src/assets/test/test.ts | 6 ------ static/assets/scripts.js | 5 ----- static/assets/scripts.js.map | 2 +- static/assets/styles.css.map | 2 +- 7 files changed, 2 insertions(+), 50 deletions(-) delete mode 100644 src/assets/test/test.django delete mode 100644 src/assets/test/test.scss delete mode 100644 src/assets/test/test.ts diff --git a/src/assets/styles.scss b/src/assets/styles.scss index dfec8f4b..45dd5f34 100644 --- a/src/assets/styles.scss +++ b/src/assets/styles.scss @@ -7,8 +7,6 @@ @import 'common/forms'; @import 'common/customize'; -// @import 'test/test'; // DEBUG - @import 'body/body'; @import 'forms/data-form'; diff --git a/src/assets/test/test.django b/src/assets/test/test.django deleted file mode 100644 index cedbd96b..00000000 --- a/src/assets/test/test.django +++ /dev/null @@ -1,22 +0,0 @@ -{# ex: set ft=htmldjango : #} - - -

Test

- -{% if settings.DEV and False %} -

ARGV: {{ settings.ARGV }}

-

DEV: {{ settings.DEV }}

-

DEBUG: {{ settings.DEBUG }}

-

RUNNING_DEVSERVER: {{ settings.RUNNING_DEVSERVER }}

-

RUNNING_MOD_WSGI: {{ settings.RUNNING_MOD_WSGI }}

-

RUNNING_MANAGE_PY: {{ settings.RUNNING_MANAGE_PY }}

-{% endif %} - -{% if settings.DEV %} -

DEV MODE

{\n const error: StripeError = result.error;\n\n if (error) {\n console.error(\n '[stripe_payment_intents_support:startStripeElementsForm:submitStripeForm] error',\n {\n error,\n event,\n params,\n stripe,\n },\n );\n\n // Show error\n const messageContainer = document.querySelector('#error-message');\n if (messageContainer) {\n messageContainer.textContent = error.message || '';\n }\n } else {\n // Success: redirect to success message\n console.log(\n '[stripe_payment_intents_support:startStripeElementsForm:submitStripeForm] success',\n {\n success_url,\n event,\n params,\n stripe,\n },\n );\n window.location.href = success_url;\n }\n })\n .catch((error) => {\n console.error(\n '[stripe_payment_intents_support:startStripeElementsForm:submitStripeForm] error',\n {\n error,\n event,\n params,\n stripe,\n },\n );\n });\n}\n\n/** Start stripe payment form */\nexport function startStripeElementsForm(params: TCreateCheckoutSessionParams) {\n const {\n STRIPE_PUBLISHABLE_KEY,\n // success_url,\n client_secret,\n } = params;\n\n // Initialize Stripe.js\n const stripe: Stripe = window.Stripe(STRIPE_PUBLISHABLE_KEY);\n\n // @see https://docs.stripe.com/js/elements_object/create_payment_element#payment_element_create-options\n const options: StripeElementsOptionsClientSecret = {\n clientSecret: client_secret,\n // TODO: Customize forms (use bootstrap styles)...\n // appearance: {},\n };\n\n // Set up Stripe.js and Elements to use in checkout form, passing the client secret obtained in a previous step\n const elements: StripeElements = stripe.elements(options);\n\n // Create and mount the Payment Element\n // @see https://docs.stripe.com/js/elements_object/create_payment_element\n const paymentElement: StripePaymentElement = elements.create('payment');\n paymentElement.mount('#payment-element');\n\n const form = document.getElementById('payment-form');\n\n if (!form) {\n const errorText = 'Form node could not be found!';\n const error = new Error(errorText);\n console.error('[stripe_payment_intents_support:startStripeElementsForm] error', errorText, {\n error,\n params,\n stripe,\n options,\n elements,\n paymentElement,\n form,\n });\n // eslint-disable-next-line no-debugger\n debugger;\n return;\n }\n\n form.addEventListener('submit', submitStripeForm.bind(null, stripe, params, elements));\n}\n","/**\n * @module test.ts\n * @changed 2024.04.04, 16:19\n */\n\n// console.log('Test', window);\n"]} \ No newline at end of file +{"version":3,"sources":["src/assets/scripts.ts","src/assets/stripe-init/stripe_payment_intents_support.ts"],"names":[],"mappings":"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","file":"scripts.js","sourcesContent":["/**\n * @desc Main js entry point module (scripts)\n * @module src/assets/scripts.ts\n * @changed 2024.04.06, 22:00\n */\n\n/* // NOTE: These modules are unused. Used only\n * // `src/assets/stripe-init/stripe_payment_intents_support.ts`, via requirejs,\n * // without exposing to global scope.\n *\n * import { startStripeElementsForm } from './stripe-init/stripe_payment_intents_support';\n *\n * console.log('[scripts] Main client code entry point', {\n * startStripeElementsForm,\n * });\n */\n\n// Empty root module\nexport {};\n","/**\n * @module stripe_payment_intents_support.ts\n * @changed 2024.04.04, 00:21\n */\n\nimport type {\n Stripe,\n StripeElements,\n StripeElementsOptionsClientSecret,\n StripeError,\n StripePaymentElement,\n} from '@stripe/stripe-js/dist/stripe-js';\n\n/** Form action */\nfunction submitStripeForm(\n stripe: Stripe,\n params: TCreateCheckoutSessionParams,\n elements: StripeElements,\n event: SubmitEvent,\n) {\n const { success_url } = params;\n\n event.preventDefault();\n\n // @see https://docs.stripe.com/payments/accept-a-payment?platform=web&ui=elements#web-submit-payment\n // TODO: Show 'busy' spinner at stripe interaction begin? (It could take some time.)\n stripe\n .confirmPayment({\n elements,\n confirmParams: {\n return_url: success_url,\n },\n })\n .then((result) => {\n const error: StripeError = result.error;\n\n if (error) {\n console.error(\n '[stripe_payment_intents_support:startStripeElementsForm:submitStripeForm] error',\n {\n error,\n event,\n params,\n stripe,\n },\n );\n\n // Show error\n const messageContainer = document.querySelector('#error-message');\n if (messageContainer) {\n messageContainer.textContent = error.message || '';\n }\n } else {\n // Success: redirect to success message\n console.log(\n '[stripe_payment_intents_support:startStripeElementsForm:submitStripeForm] success',\n {\n success_url,\n event,\n params,\n stripe,\n },\n );\n window.location.href = success_url;\n }\n })\n .catch((error) => {\n console.error(\n '[stripe_payment_intents_support:startStripeElementsForm:submitStripeForm] error',\n {\n error,\n event,\n params,\n stripe,\n },\n );\n });\n}\n\n/** Start stripe payment form */\nexport function startStripeElementsForm(params: TCreateCheckoutSessionParams) {\n const {\n STRIPE_PUBLISHABLE_KEY,\n // success_url,\n client_secret,\n } = params;\n\n // Initialize Stripe.js\n const stripe: Stripe = window.Stripe(STRIPE_PUBLISHABLE_KEY);\n\n // @see https://docs.stripe.com/js/elements_object/create_payment_element#payment_element_create-options\n const options: StripeElementsOptionsClientSecret = {\n clientSecret: client_secret,\n // TODO: Customize forms (use bootstrap styles)...\n // appearance: {},\n };\n\n // Set up Stripe.js and Elements to use in checkout form, passing the client secret obtained in a previous step\n const elements: StripeElements = stripe.elements(options);\n\n // Create and mount the Payment Element\n // @see https://docs.stripe.com/js/elements_object/create_payment_element\n const paymentElement: StripePaymentElement = elements.create('payment');\n paymentElement.mount('#payment-element');\n\n const form = document.getElementById('payment-form');\n\n if (!form) {\n const errorText = 'Form node could not be found!';\n const error = new Error(errorText);\n console.error('[stripe_payment_intents_support:startStripeElementsForm] error', errorText, {\n error,\n params,\n stripe,\n options,\n elements,\n paymentElement,\n form,\n });\n // eslint-disable-next-line no-debugger\n debugger;\n return;\n }\n\n form.addEventListener('submit', submitStripeForm.bind(null, stripe, params, elements));\n}\n"]} \ No newline at end of file diff --git a/static/assets/styles.css.map b/static/assets/styles.css.map index c99a7d9c..db4054c6 100644 --- a/static/assets/styles.css.map +++ b/static/assets/styles.css.map @@ -1 +1 @@ -{"version":3,"sources":["styles.scss","common/common.scss","styles.css","shared/variables.scss","common/forms.scss","common/customize.scss","body/body.scss","forms/data-form.scss","theme/bootstrap-theme-fixes.scss","page-header-navbar/page-header-navbar.scss","shared/mixins.scss","page-footer-navbar/page-footer-navbar.scss","main-page-splash/main-page-splash.scss","membership-splash/membership-splash.scss","events-list-table/events-list-table.scss","events-list-block/events-list-block.scss"],"names":[],"mappings":"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","file":"styles.css","sourcesContent":["/**\n * @module styles.scss\n * @changed 2024.04.08, 19:38\n */\n\n@import 'common/common';\n@import 'common/forms';\n@import 'common/customize';\n\n// @import 'test/test'; // DEBUG\n\n@import 'body/body';\n@import 'forms/data-form';\n\n@import 'theme/bootstrap-theme-fixes';\n\n@import 'page-header-navbar/page-header-navbar';\n@import 'page-footer-navbar/page-footer-navbar';\n\n@import 'main-page-splash/main-page-splash';\n@import 'membership-splash/membership-splash';\n\n@import 'events-list-table/events-list-table';\n@import 'events-list-block/events-list-block';\n\n// @import 'membership-choose-list/membership-choose-list'; // UNUSED?\n","/**\n * @module common.scss\n * @changed 2024.03.08, 12:00\n */\n\n@import '../shared';\n\n.item-label,\n.dimmed-info {\n opacity: 0.5;\n}\n.primary-color {\n color: $primaryColor;\n}\n.optional-message:empty {\n display: none;\n}\n\n.common-actions {\n a:not(.btn) {\n margin-left: 8px;\n margin-right: 8px;\n }\n}\n","/**\n * @module styles.scss\n * @changed 2024.04.08, 19:38\n */\n/**\n * @module common.scss\n * @changed 2024.03.08, 12:00\n */\n.item-label,\n.dimmed-info {\n opacity: 0.5;\n}\n\n.primary-color {\n color: #486;\n}\n\n.optional-message:empty {\n display: none;\n}\n\n.common-actions a:not(.btn) {\n margin-left: 8px;\n margin-right: 8px;\n}\n\n/**\n * @module forms.scss\n * @changed 2024.03.08, 12:00\n */\n.asteriskField {\n display: inline-block;\n margin-left: 4px;\n opacity: 0.5;\n}\n\n/**\n * @module customize.scss\n * @changed 2024.03.11, 13:52\n */\n:root {\n --bs-body-font-family: Roboto, Helvetica, Arial, sans-serif;\n}\n\n/**\n * @module body\n * @changed 2024.03.08, 13:30\n */\nbody {\n font-family: \"Roboto\", \"Helvetica\", \"Arial\", sans-serif;\n background-color: #fff;\n margin-top: 80px;\n}\n\n.data-form .form-group {\n margin-top: 8px;\n margin-bottom: 8px;\n}\n\n/**\n * @module bootstrap-theme-fixes\n * @changed 2024.04.02, 16:21\n */\n:root {\n --bs-primary-rgb: 68, 136, 102;\n --bs-link-color-rgb: var(--bs-primary-rgb);\n --bs-link-color: #486;\n --bs-link-hover-color: #24533c;\n --bs-link-hover-color-rgb: var(--bs-link-hover-color);\n}\n\n.btn-primary {\n --bs-btn-bg: #486;\n --bs-btn-border-color: #486;\n --bs-btn-hover-bg: #375;\n --bs-btn-hover-border-color: #24533c;\n --bs-btn-focus-shadow-rgb: #8a9;\n --bs-btn-active-bg: #24533c;\n --bs-btn-active-border-color: #24533c;\n --bs-btn-disabled-bg: #486;\n --bs-btn-disabled-border-color: #486;\n}\n\n.btn-outline-primary {\n --bs-btn-color: #486;\n --bs-btn-border-color: #486;\n --bs-btn-hover-bg: #486;\n --bs-btn-hover-border-color: #486;\n --bs-btn-focus-shadow-rgb: #486;\n --bs-btn-active-bg: #486;\n --bs-btn-active-border-color: #486;\n --bs-btn-disabled-color: #486;\n --bs-btn-disabled-border-color: #486;\n}\n\n.btn-outline-primary.btn-link {\n text-decoration: none;\n}\n.btn-outline-primary.btn-link:active, .btn-outline-primary.btn-link:hover {\n color: #fff;\n}\n\n.progress,\n.progress-stacked {\n --bs-progress-bar-bg: #486;\n}\n\n.list-group {\n --bs-list-group-active-bg: #486;\n --bs-list-group-active-border-color: #486;\n}\n\n.btn:focus-visible,\n.btn-check:checked + .btn:focus-visible,\n:not(.btn-check) + .btn:active:focus-visible,\n.btn:first-child:active:focus-visible,\n.btn.active:focus-visible,\n.btn.show:focus-visible,\n.form-check-input:focus,\n.form-select:focus,\n.form-control:focus {\n box-shadow: 0 0 0 0.25rem rgba(136, 170, 153, 0.25);\n border-color: #8a9;\n}\n\n.form-check-input:checked {\n background-color: #486;\n border-color: #486;\n}\n\n.table-primary-header thead th {\n background-color: #486;\n color: #fff;\n}\n.table-primary-header th,\n.table-primary-header td {\n border-right-width: var(--bs-border-width);\n}\n.table-primary-header th:first-child,\n.table-primary-header td:first-child {\n border-left-width: var(--bs-border-width);\n}\n\n.btn-icon {\n padding-left: 0;\n padding-right: 0;\n width: 38px;\n height: 38px;\n}\n.btn-icon, .btn-icon > i {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n/**\n * @module page-header-navbar.scss\n * @changed 2024.03.08, 12:00\n */\n.page-header-navbar {\n padding: 0;\n}\n.page-header-navbar .main-bar {\n flex: 1;\n display: flex;\n width: 100%;\n align-items: center;\n}\n.page-header-navbar .navbar-brand {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.page-header-navbar.navbar-dark.navbar-primary {\n background-color: #375;\n color: #fff;\n}\n.page-header-navbar.navbar-dark.navbar-primary:before {\n display: block;\n content: \" \";\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n background-image: url(\"/static/images/splash/curves-bg/curves-x.svg\");\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.page-header-navbar.navbar-dark.navbar-primary .container-fluid {\n z-index: 1;\n}\n.page-header-navbar .dropdown-menu#user-menu {\n right: 0;\n left: auto;\n}\n@media (max-width: 400px) {\n .page-header-navbar .site-name {\n display: none;\n }\n}\n@media (min-width: 992px) {\n .page-header-navbar .navbar-brand {\n flex: 1;\n }\n .page-header-navbar .collapse.navbar-collapse {\n flex: 0;\n }\n}\n.page-header-navbar .nav-link {\n white-space: nowrap;\n color: #fff;\n transition: all 250ms;\n opacity: 0.85;\n}\n.page-header-navbar .nav-link:hover {\n opacity: 1;\n}\n\n/**\n * @module page-footer-navbar\n * @changed 2024.03.08, 13:30\n */\n.page-footer-navbar {\n border-top: 1px solid #eee;\n font-size: 90%;\n margin-bottom: 0;\n margin-top: 20px;\n padding: 0;\n}\n.page-footer-navbar .container-fluid {\n display: flex;\n flex-direction: column;\n flex-wrap: wrap;\n align-content: center;\n align-items: center;\n justify-content: space-between;\n}\n.page-footer-navbar .container-fluid .navbar-right {\n display: flex;\n flex-wrap: wrap;\n}\n@media (min-width: 576px) {\n .page-footer-navbar .container-fluid {\n flex-direction: row;\n }\n .page-footer-navbar .container-fluid .navbar-copyright,\n .page-footer-navbar .container-fluid .navbar-middle,\n .page-footer-navbar .container-fluid .navbar-right {\n flex: 1;\n }\n .page-footer-navbar .container-fluid .navbar-right {\n justify-content: flex-end;\n }\n}\n.page-footer-navbar .navbar-copyright {\n display: flex;\n align-items: center;\n}\n.page-footer-navbar .navbar-nav {\n margin: 0;\n flex-direction: row;\n}\n.page-footer-navbar .navbar-nav .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n}\n\n/**\n * @module main-page-splash\n * @changed 2024.03.08, 17:06\n */\n.main-page-splash {\n background-color: #375;\n color: #fff;\n position: relative;\n}\n.main-page-splash:before {\n display: block;\n content: \" \";\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n background-image: url(\"/static/images/splash/curves-bg/curves-x.svg\");\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.main-page-splash .container-fluid {\n z-index: 1;\n}\n.main-page-splash > .content {\n position: relative;\n}\n.main-page-splash > .content h1 {\n font-weight: 400;\n}\n\n/**\n * @module membership-splash\n * @changed 2024.03.08, 17:06\n */\n.membership-splash {\n overflow: hidden;\n position: relative;\n padding: 12px;\n}\n.membership-splash.dark {\n background-color: #375;\n color: #fff;\n}\n.membership-splash.dark:before {\n display: block;\n content: \" \";\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n background-image: url(\"/static/images/splash/curves-bg/curves-x.svg\");\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.membership-splash.dark .container-fluid {\n z-index: 1;\n}\n.membership-splash.light {\n background-color: rgba(136, 170, 153, 0.1);\n}\n.membership-splash.light:before {\n display: block;\n content: \" \";\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n background-image: url(\"/static/images/splash/curves-bg/curves-x.svg\");\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.membership-splash.light .container-fluid {\n z-index: 1;\n}\n.membership-splash > .content {\n position: relative;\n}\n.membership-splash .content-cell {\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 2;\n}\n.membership-splash .content-block {\n padding-top: 1em;\n}\n.membership-splash .content-block h1 {\n font-weight: 300;\n}\n@media (min-width: 768px) {\n .membership-splash .content-block {\n font-size: 120%;\n }\n .membership-splash .content-block h1 {\n font-size: 180%;\n }\n}\n@media (min-width: 992px) {\n .membership-splash .content-block {\n font-size: 140%;\n }\n .membership-splash .content-block h1 {\n font-size: 200%;\n }\n}\n.membership-splash.membership-splash-default .content-block {\n max-width: 480px;\n}\n.membership-splash.membership-splash-user .content-block {\n max-width: 720px;\n}\n.membership-splash .visual-cell {\n background-image: url(\"/static/images/splash/membership/dds-painting.png\");\n background-position: center;\n background-repeat: no-repeat;\n background-size: contain;\n min-height: 320px;\n align-self: flex-start;\n}\n@media (max-width: 992px) {\n .membership-splash .visual-cell {\n display: none;\n }\n}\n.membership-splash a:not(.btn) {\n color: #fff;\n transition: all 250ms;\n text-decoration-thickness: 2px;\n text-decoration-line: underline;\n opacity: 0.8;\n}\n.membership-splash a:not(.btn):hover {\n opacity: 1;\n}\n\n/**\n * @module events-list-table.scss\n * @changed 2024.03.21, 16:50\n */\n.events-list-table {\n /*\n .col-registration\n .col-event\n .col-participants\n .col-opens\n .col-closes\n .col-payment\n .col-options\n .col-paid\n .col-actions\n */\n}\n.events-list-table .col-actions,\n.events-list-table .col-payment,\n.events-list-table .col-registration,\n.events-list-table .col-participants,\n.events-list-table .col-paid {\n text-align: center;\n}\n.events-list-table tbody th,\n.events-list-table tbody td {\n vertical-align: middle;\n}\n.events-list-table tbody .col-event {\n color: #486;\n}\n.events-list-table tbody .col-actions-wrapper {\n display: flex;\n gap: 4px;\n justify-content: center;\n flex-wrap: wrap;\n}\n\n/**\n * @module events-list.scss\n * @changed 2024.03.18, 00:57\n */\n.events-list-block {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.events-list-block .events-list-item {\n padding: 16px;\n border-radius: 8px;\n}\n.events-list-block .events-list-item.has-registration {\n background-color: rgba(136, 170, 153, 0.25);\n}\n.events-list-block .events-list-item > * {\n margin-bottom: 0.5rem;\n}\n.events-list-block .events-list-item-title {\n color: #486;\n font-weight: 400;\n}\n.events-list-block .events-list-item-details {\n display: flex;\n flex-wrap: wrap;\n gap: 0.1rem 1rem;\n}","@use 'sass:map';\n@use 'sass:math';\n@use 'sass:color';\n\n@import '../../vendor/bootstrap-5.3.2/scss/functions';\n@import '../../vendor/bootstrap-5.3.2/scss/variables';\n\n// Font...\n\n$defaultFontSize: 14px;\n\n$defaultFontFamily: 'Roboto', 'Helvetica', 'Arial', sans-serif;\n// $defaultFontFamily: Roboto, system-ui, -apple-system, \"Segoe UI\", \"Helvetica Neue\", \"Noto Sans\", \"Liberation Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n\n// Breakpoints:...\n\n// Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`:\n// - xs: 0\n// - sm: 576px\n// - md: 768px\n// - lg: 992px\n// - xl: 1200px\n// - xxl: 1400px\n\n$screenXsMin: map.get($grid-breakpoints, 'xs'); // 0\n$screenSmMin: map.get($grid-breakpoints, 'sm'); // 576px\n$screenMdMin: map.get($grid-breakpoints, 'md'); // 768px\n$screenLgMin: map.get($grid-breakpoints, 'lg'); // 992px\n$screenXlMin: map.get($grid-breakpoints, 'xl'); // 1200px\n$screenXxlMin: map.get($grid-breakpoints, 'xxl'); // 1400px\n\n$screenXsMax: map.get($grid-breakpoints, 'sm'); // 576px\n$screenSmMax: map.get($grid-breakpoints, 'md'); // 768px\n$screenMdMax: map.get($grid-breakpoints, 'lg'); // 992px\n$screenLgMax: map.get($grid-breakpoints, 'xl'); // 1200px\n$screenXlMax: map.get($grid-breakpoints, 'xxl'); // 1400px\n\n// Collapsable widths...\n\n$collapseWidth: screenMdMin; // $grid-float-breakpoint; // =@screen-sm-min=768px ? =@screen-md-min=992px\n$navbarCollapse: $screenLgMin;\n$navbarCollapseMax: $screenMdMax;\n$midbarCollapse: $collapseWidth;\n\n// Primary color...\n\n$primaryLightColor: #8a9;\n$primaryColor: #486;\n$primaryDarkColor: #375;\n$primaryDarkenColor: color.adjust($primaryDarkColor, $lightness: -10%);\n$primaryDarkestColor: #3c5343;\n\n$primaryColorRgb: 68, 136, 102;\n\n// Misc colors...\n\n// UNUSED?\n$xdarkBlueColor: #036;\n$darkBlueColor: #047;\n$mediumBlueColor: #157;\n$moodBlueColor: #6ac;\n$extralightBlueColor: #def;\n\n$darkGreenColor: #461;\n$mediumGreenColor: #9a0;\n\n$defaultTextColor: #333;\n\n$backgroundColor: #fff;\n\n// Navbar...\n\n$navbarMainHeight: 60px;\n$navbarPlusHeight: 50px;\n\n// Timeouts...\n\n$momentTime: 150ms;\n$transitionTime: 250ms;\n$animationTime: 500ms;\n$effectTime: 1000ms;\n","/**\n * @module forms.scss\n * @changed 2024.03.08, 12:00\n */\n\n@import '../shared';\n\n.asteriskField {\n // crispy_forms element\n display: inline-block;\n margin-left: 4px;\n opacity: 0.5;\n}\n","/**\n * @module customize.scss\n * @changed 2024.03.11, 13:52\n */\n\n@import '../shared';\n\n:root {\n // --bs-body-font-size: #{$defaultFontSize};\n --bs-body-font-family: #{$defaultFontFamily};\n}\n","/**\n * @module body\n * @changed 2024.03.08, 13:30\n */\n\n@import '../shared';\n\n$headerNavbarHeight: 60px;\n\nbody {\n font-family: $defaultFontFamily;\n background-color: $backgroundColor;\n // Add space for fixed navar (see `static/assets/page-header-navbar/page-header-navbar.django`)\n margin-top: $headerNavbarHeight + 20px;\n}\n",".data-form {\n .form-group {\n margin-top: 8px;\n margin-bottom: 8px;\n }\n}\n","/**\n * @module bootstrap-theme-fixes\n * @changed 2024.04.02, 16:21\n */\n\n@use 'sass:color';\n\n@import '../shared';\n\n:root {\n --bs-primary-rgb: #{$primaryColorRgb};\n --bs-link-color-rgb: var(--bs-primary-rgb);\n --bs-link-color: #{$primaryColor}; // #0d6efd;\n // --bs-link-color-rgb: 13, 110, 253;\n // --bs-link-decoration: underline;\n --bs-link-hover-color: #{$primaryDarkenColor}; // #0a58ca;\n --bs-link-hover-color-rgb: var(--bs-link-hover-color);\n // --bs-link-hover-color-rgb: 10, 88, 202;\n // --bs-border-color: #{$primaryColor};\n}\n\n.btn-primary {\n // --bs-btn-color: #fff;\n --bs-btn-bg: #{$primaryColor}; // #0d6efd;\n --bs-btn-border-color: #{$primaryColor}; // #0d6efd;\n // --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #{$primaryDarkColor}; // #0b5ed7;\n --bs-btn-hover-border-color: #{$primaryDarkenColor}; // #0a58ca;\n --bs-btn-focus-shadow-rgb: #{$primaryLightColor}; // #3184fd; // 49, 132, 253;\n // --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #{$primaryDarkenColor}; // #0a58ca;\n --bs-btn-active-border-color: #{$primaryDarkenColor}; // #0a53be;\n // --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n // --bs-btn-disabled-color: #fff;\n --bs-btn-disabled-bg: #{$primaryColor}; // #0d6efd;\n --bs-btn-disabled-border-color: #{$primaryColor}; // #0d6efd;\n}\n\n.btn-outline-primary {\n --bs-btn-color: #{$primaryColor}; // #0d6efd\n --bs-btn-border-color: #{$primaryColor}; // #0d6efd\n // --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #{$primaryColor}; // #0d6efd\n --bs-btn-hover-border-color: #{$primaryColor}; // #0d6efd\n --bs-btn-focus-shadow-rgb: #{$primaryColor}; // #0d6efd\n // --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #{$primaryColor}; // #0d6efd\n --bs-btn-active-border-color: #{$primaryColor}; // #0d6efd\n // --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #{$primaryColor}; // #0d6efd\n // --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #{$primaryColor}; // #0d6efd\n // --bs-gradient: none;\n}\n\n// Fix hover styles for combined primary outlined and link buttons\n.btn-outline-primary.btn-link {\n &:active,\n &:hover {\n color: #fff;\n }\n text-decoration: none;\n}\n\n.progress,\n.progress-stacked {\n // --bs-progress-height: 1rem;\n // --bs-progress-font-size: 0.75rem;\n // --bs-progress-bg: var(--bs-secondary-bg);\n // --bs-progress-border-radius: var(--bs-border-radius);\n // --bs-progress-box-shadow: var(--bs-box-shadow-inset);\n // --bs-progress-bar-color: #fff;\n --bs-progress-bar-bg: #{$primaryColor}; // #0d6efd;\n // --bs-progress-bar-transition: width 0.6s ease;\n}\n\n.list-group {\n // --bs-list-group-color: var(--bs-body-color);\n // --bs-list-group-bg: var(--bs-body-bg);\n // --bs-list-group-border-color: var(--bs-border-color);\n // --bs-list-group-border-width: var(--bs-border-width);\n // --bs-list-group-border-radius: var(--bs-border-radius);\n // --bs-list-group-item-padding-x: 1rem;\n // --bs-list-group-item-padding-y: 0.5rem;\n // --bs-list-group-action-color: var(--bs-secondary-color);\n // --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n // --bs-list-group-action-hover-bg: var(--bs-tertiary-bg);\n // --bs-list-group-action-active-color: var(--bs-body-color);\n // --bs-list-group-action-active-bg: var(--bs-secondary-bg);\n // --bs-list-group-disabled-color: var(--bs-secondary-color);\n // --bs-list-group-disabled-bg: var(--bs-body-bg);\n // --bs-list-group-active-color: #fff;\n --bs-list-group-active-bg: #{$primaryColor}; // #0d6efd;\n --bs-list-group-active-border-color: #{$primaryColor}; // #0d6efd;\n}\n\n.btn:focus-visible,\n.btn-check:checked + .btn:focus-visible,\n:not(.btn-check) + .btn:active:focus-visible,\n.btn:first-child:active:focus-visible,\n.btn.active:focus-visible,\n.btn.show:focus-visible,\n.form-check-input:focus,\n.form-select:focus,\n.form-control:focus {\n box-shadow: 0 0 0 0.25rem color.change($primaryLightColor, $alpha: 0.25);\n border-color: $primaryLightColor;\n}\n\n.form-check-input:checked {\n background-color: $primaryColor;\n border-color: $primaryColor;\n}\n\n.table-primary-header {\n thead th {\n background-color: $primaryColor;\n color: #fff;\n }\n th,\n td {\n border-right-width: var(--bs-border-width);\n &:first-child {\n border-left-width: var(--bs-border-width);\n }\n }\n}\n\n.btn-icon {\n padding-left: 0;\n padding-right: 0;\n // For md size:\n width: 38px;\n height: 38px;\n &,\n & > i {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n }\n}\n","/**\n * @module page-header-navbar.scss\n * @changed 2024.03.08, 12:00\n */\n\n@import '../shared';\n\n.page-header-navbar {\n padding: 0;\n // Adaptive layout: trim too long title string with an ellipsis...\n .main-bar {\n flex: 1;\n display: flex;\n width: 100%;\n align-items: center;\n }\n .navbar-brand {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n // Dark primary navbar with background decor...\n &.navbar-dark.navbar-primary {\n @include themeBackgroundBefore;\n }\n .dropdown-menu#user-menu {\n // Position dropdown popup relative to the right screen side (as the menu is positioned to the right)\n right: 0;\n left: auto;\n }\n @media (max-width: 400px) {\n .site-name {\n display: none;\n }\n }\n @media (min-width: $navbarCollapse) {\n .navbar-brand {\n flex: 1;\n }\n .collapse.navbar-collapse {\n flex: 0;\n }\n }\n .nav-link {\n white-space: nowrap;\n color: #fff;\n transition: all $transitionTime;\n opacity: 0.85;\n &:hover {\n opacity: 1;\n }\n }\n}\n","@mixin themeBackground {\n background-image: url('/static/images/splash/curves-bg/curves-x.svg');\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n@mixin themeBackgroundBaseBefore {\n &:before {\n display: block;\n content: ' ';\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n @include themeBackground;\n }\n .container-fluid {\n z-index: 1;\n }\n}\n@mixin themeBackgroundBefore {\n background-color: $primaryDarkColor;\n color: #fff;\n @include themeBackgroundBaseBefore;\n}\n","/**\n * @module page-footer-navbar\n * @changed 2024.03.08, 13:30\n */\n\n.page-footer-navbar {\n $borderColor: #eee;\n border-top: 1px solid $borderColor;\n font-size: 90%;\n // border-bottom: 1px solid $borderColor;\n margin-bottom: 0;\n margin-top: 20px;\n padding: 0;\n .container-fluid {\n display: flex;\n flex-direction: column;\n flex-wrap: wrap;\n align-content: center;\n align-items: center;\n justify-content: space-between;\n .navbar-right {\n display: flex;\n flex-wrap: wrap;\n }\n @media (min-width: $screenSmMin) {\n flex-direction: row;\n .navbar-copyright,\n .navbar-middle,\n .navbar-right {\n flex: 1;\n }\n .navbar-copyright {\n }\n .navbar-middle {\n }\n .navbar-right {\n justify-content: flex-end;\n }\n }\n }\n .navbar-copyright {\n display: flex;\n align-items: center;\n // gap: 10px;\n }\n .navbar-nav {\n margin: 0;\n flex-direction: row;\n .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n }\n }\n}\n","/**\n * @module main-page-splash\n * @changed 2024.03.08, 17:06\n */\n\n@import '../shared';\n\n.main-page-splash {\n @include themeBackgroundBefore;\n position: relative;\n > .content {\n h1 {\n font-weight: 400;\n }\n position: relative;\n }\n}\n","/**\n * @module membership-splash\n * @changed 2024.03.08, 17:06\n */\n\n@use 'sass:color';\n\n@import '../shared';\n\n.membership-splash {\n overflow: hidden;\n position: relative;\n padding: 12px;\n // Theming...\n &.dark {\n @include themeBackgroundBefore;\n }\n &.light {\n background-color: color.change($primaryLightColor, $alpha: 0.1);\n @include themeBackgroundBaseBefore;\n }\n // Ensure z-index for content...\n > .content {\n position: relative;\n }\n .content-cell {\n // text-align: center;\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 2;\n }\n .content-block {\n padding-top: 1em;\n h1 {\n font-weight: 300;\n }\n @media (min-width: $screenMdMin) {\n font-size: 120%;\n h1 {\n font-size: 180%;\n }\n }\n @media (min-width: $screenLgMin) {\n font-size: 140%;\n h1 {\n font-size: 200%;\n }\n }\n }\n &.membership-splash-default .content-block {\n max-width: 480px;\n }\n &.membership-splash-user .content-block {\n max-width: 720px;\n }\n .visual-cell {\n @media (max-width: $screenMdMax) {\n // Hide on small screens\n display: none;\n }\n background-image: url('/static/images/splash/membership/dds-painting.png');\n background-position: center;\n background-repeat: no-repeat;\n background-size: contain;\n min-height: 320px;\n align-self: flex-start;\n }\n a:not(.btn) {\n color: #fff;\n transition: all $transitionTime;\n text-decoration-thickness: 2px;\n text-decoration-line: underline;\n opacity: 0.8;\n &:hover {\n opacity: 1;\n }\n }\n}\n","/**\n * @module events-list-table.scss\n * @changed 2024.03.21, 16:50\n */\n\n@import '../shared';\n\n.events-list-table {\n /*\n .col-registration\n .col-event\n .col-participants\n .col-opens\n .col-closes\n .col-payment\n .col-options\n .col-paid\n .col-actions\n */\n\n .col-actions,\n .col-payment,\n .col-registration,\n .col-participants,\n .col-paid {\n text-align: center;\n }\n\n tbody {\n th,\n td {\n vertical-align: middle;\n }\n .col-event {\n color: $primaryColor;\n }\n .col-actions-wrapper {\n display: flex;\n gap: 4px;\n justify-content: center;\n flex-wrap: wrap;\n }\n }\n}\n","/**\n * @module events-list.scss\n * @changed 2024.03.18, 00:57\n */\n\n@use 'sass:color';\n\n@import '../shared';\n\n.events-list-block {\n display: flex;\n flex-direction: column;\n gap: 8px;\n .events-list-item {\n padding: 16px;\n border-radius: 8px;\n &.has-registration {\n background-color: color.change($primaryLightColor, $alpha: 0.25);\n }\n & > * {\n margin-bottom: 0.5rem;\n }\n }\n .events-list-item-title {\n color: $primaryColor;\n font-weight: 400;\n }\n .events-list-item-details {\n display: flex;\n flex-wrap: wrap;\n gap: 0.1rem 1rem;\n }\n}\n"]} \ No newline at end of file +{"version":3,"sources":["styles.scss","common/common.scss","styles.css","shared/variables.scss","common/forms.scss","common/customize.scss","body/body.scss","forms/data-form.scss","theme/bootstrap-theme-fixes.scss","page-header-navbar/page-header-navbar.scss","shared/mixins.scss","page-footer-navbar/page-footer-navbar.scss","main-page-splash/main-page-splash.scss","membership-splash/membership-splash.scss","events-list-table/events-list-table.scss","events-list-block/events-list-block.scss"],"names":[],"mappings":"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","file":"styles.css","sourcesContent":["/**\n * @module styles.scss\n * @changed 2024.04.08, 19:38\n */\n\n@import 'common/common';\n@import 'common/forms';\n@import 'common/customize';\n\n@import 'body/body';\n@import 'forms/data-form';\n\n@import 'theme/bootstrap-theme-fixes';\n\n@import 'page-header-navbar/page-header-navbar';\n@import 'page-footer-navbar/page-footer-navbar';\n\n@import 'main-page-splash/main-page-splash';\n@import 'membership-splash/membership-splash';\n\n@import 'events-list-table/events-list-table';\n@import 'events-list-block/events-list-block';\n\n// @import 'membership-choose-list/membership-choose-list'; // UNUSED?\n","/**\n * @module common.scss\n * @changed 2024.03.08, 12:00\n */\n\n@import '../shared';\n\n.item-label,\n.dimmed-info {\n opacity: 0.5;\n}\n.primary-color {\n color: $primaryColor;\n}\n.optional-message:empty {\n display: none;\n}\n\n.common-actions {\n a:not(.btn) {\n margin-left: 8px;\n margin-right: 8px;\n }\n}\n","/**\n * @module styles.scss\n * @changed 2024.04.08, 19:38\n */\n/**\n * @module common.scss\n * @changed 2024.03.08, 12:00\n */\n.item-label,\n.dimmed-info {\n opacity: 0.5;\n}\n\n.primary-color {\n color: #486;\n}\n\n.optional-message:empty {\n display: none;\n}\n\n.common-actions a:not(.btn) {\n margin-left: 8px;\n margin-right: 8px;\n}\n\n/**\n * @module forms.scss\n * @changed 2024.03.08, 12:00\n */\n.asteriskField {\n display: inline-block;\n margin-left: 4px;\n opacity: 0.5;\n}\n\n/**\n * @module customize.scss\n * @changed 2024.03.11, 13:52\n */\n:root {\n --bs-body-font-family: Roboto, Helvetica, Arial, sans-serif;\n}\n\n/**\n * @module body\n * @changed 2024.03.08, 13:30\n */\nbody {\n font-family: \"Roboto\", \"Helvetica\", \"Arial\", sans-serif;\n background-color: #fff;\n margin-top: 80px;\n}\n\n.data-form .form-group {\n margin-top: 8px;\n margin-bottom: 8px;\n}\n\n/**\n * @module bootstrap-theme-fixes\n * @changed 2024.04.02, 16:21\n */\n:root {\n --bs-primary-rgb: 68, 136, 102;\n --bs-link-color-rgb: var(--bs-primary-rgb);\n --bs-link-color: #486;\n --bs-link-hover-color: #24533c;\n --bs-link-hover-color-rgb: var(--bs-link-hover-color);\n}\n\n.btn-primary {\n --bs-btn-bg: #486;\n --bs-btn-border-color: #486;\n --bs-btn-hover-bg: #375;\n --bs-btn-hover-border-color: #24533c;\n --bs-btn-focus-shadow-rgb: #8a9;\n --bs-btn-active-bg: #24533c;\n --bs-btn-active-border-color: #24533c;\n --bs-btn-disabled-bg: #486;\n --bs-btn-disabled-border-color: #486;\n}\n\n.btn-outline-primary {\n --bs-btn-color: #486;\n --bs-btn-border-color: #486;\n --bs-btn-hover-bg: #486;\n --bs-btn-hover-border-color: #486;\n --bs-btn-focus-shadow-rgb: #486;\n --bs-btn-active-bg: #486;\n --bs-btn-active-border-color: #486;\n --bs-btn-disabled-color: #486;\n --bs-btn-disabled-border-color: #486;\n}\n\n.btn-outline-primary.btn-link {\n text-decoration: none;\n}\n.btn-outline-primary.btn-link:active, .btn-outline-primary.btn-link:hover {\n color: #fff;\n}\n\n.progress,\n.progress-stacked {\n --bs-progress-bar-bg: #486;\n}\n\n.list-group {\n --bs-list-group-active-bg: #486;\n --bs-list-group-active-border-color: #486;\n}\n\n.btn:focus-visible,\n.btn-check:checked + .btn:focus-visible,\n:not(.btn-check) + .btn:active:focus-visible,\n.btn:first-child:active:focus-visible,\n.btn.active:focus-visible,\n.btn.show:focus-visible,\n.form-check-input:focus,\n.form-select:focus,\n.form-control:focus {\n box-shadow: 0 0 0 0.25rem rgba(136, 170, 153, 0.25);\n border-color: #8a9;\n}\n\n.form-check-input:checked {\n background-color: #486;\n border-color: #486;\n}\n\n.table-primary-header thead th {\n background-color: #486;\n color: #fff;\n}\n.table-primary-header th,\n.table-primary-header td {\n border-right-width: var(--bs-border-width);\n}\n.table-primary-header th:first-child,\n.table-primary-header td:first-child {\n border-left-width: var(--bs-border-width);\n}\n\n.btn-icon {\n padding-left: 0;\n padding-right: 0;\n width: 38px;\n height: 38px;\n}\n.btn-icon, .btn-icon > i {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n/**\n * @module page-header-navbar.scss\n * @changed 2024.03.08, 12:00\n */\n.page-header-navbar {\n padding: 0;\n}\n.page-header-navbar .main-bar {\n flex: 1;\n display: flex;\n width: 100%;\n align-items: center;\n}\n.page-header-navbar .navbar-brand {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.page-header-navbar.navbar-dark.navbar-primary {\n background-color: #375;\n color: #fff;\n}\n.page-header-navbar.navbar-dark.navbar-primary:before {\n display: block;\n content: \" \";\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n background-image: url(\"/static/images/splash/curves-bg/curves-x.svg\");\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.page-header-navbar.navbar-dark.navbar-primary .container-fluid {\n z-index: 1;\n}\n.page-header-navbar .dropdown-menu#user-menu {\n right: 0;\n left: auto;\n}\n@media (max-width: 400px) {\n .page-header-navbar .site-name {\n display: none;\n }\n}\n@media (min-width: 992px) {\n .page-header-navbar .navbar-brand {\n flex: 1;\n }\n .page-header-navbar .collapse.navbar-collapse {\n flex: 0;\n }\n}\n.page-header-navbar .nav-link {\n white-space: nowrap;\n color: #fff;\n transition: all 250ms;\n opacity: 0.85;\n}\n.page-header-navbar .nav-link:hover {\n opacity: 1;\n}\n\n/**\n * @module page-footer-navbar\n * @changed 2024.03.08, 13:30\n */\n.page-footer-navbar {\n border-top: 1px solid #eee;\n font-size: 90%;\n margin-bottom: 0;\n margin-top: 20px;\n padding: 0;\n}\n.page-footer-navbar .container-fluid {\n display: flex;\n flex-direction: column;\n flex-wrap: wrap;\n align-content: center;\n align-items: center;\n justify-content: space-between;\n}\n.page-footer-navbar .container-fluid .navbar-right {\n display: flex;\n flex-wrap: wrap;\n}\n@media (min-width: 576px) {\n .page-footer-navbar .container-fluid {\n flex-direction: row;\n }\n .page-footer-navbar .container-fluid .navbar-copyright,\n .page-footer-navbar .container-fluid .navbar-middle,\n .page-footer-navbar .container-fluid .navbar-right {\n flex: 1;\n }\n .page-footer-navbar .container-fluid .navbar-right {\n justify-content: flex-end;\n }\n}\n.page-footer-navbar .navbar-copyright {\n display: flex;\n align-items: center;\n}\n.page-footer-navbar .navbar-nav {\n margin: 0;\n flex-direction: row;\n}\n.page-footer-navbar .navbar-nav .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n}\n\n/**\n * @module main-page-splash\n * @changed 2024.03.08, 17:06\n */\n.main-page-splash {\n background-color: #375;\n color: #fff;\n position: relative;\n}\n.main-page-splash:before {\n display: block;\n content: \" \";\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n background-image: url(\"/static/images/splash/curves-bg/curves-x.svg\");\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.main-page-splash .container-fluid {\n z-index: 1;\n}\n.main-page-splash > .content {\n position: relative;\n}\n.main-page-splash > .content h1 {\n font-weight: 400;\n}\n\n/**\n * @module membership-splash\n * @changed 2024.03.08, 17:06\n */\n.membership-splash {\n overflow: hidden;\n position: relative;\n padding: 12px;\n}\n.membership-splash.dark {\n background-color: #375;\n color: #fff;\n}\n.membership-splash.dark:before {\n display: block;\n content: \" \";\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n background-image: url(\"/static/images/splash/curves-bg/curves-x.svg\");\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.membership-splash.dark .container-fluid {\n z-index: 1;\n}\n.membership-splash.light {\n background-color: rgba(136, 170, 153, 0.1);\n}\n.membership-splash.light:before {\n display: block;\n content: \" \";\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n background-image: url(\"/static/images/splash/curves-bg/curves-x.svg\");\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n.membership-splash.light .container-fluid {\n z-index: 1;\n}\n.membership-splash > .content {\n position: relative;\n}\n.membership-splash .content-cell {\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 2;\n}\n.membership-splash .content-block {\n padding-top: 1em;\n}\n.membership-splash .content-block h1 {\n font-weight: 300;\n}\n@media (min-width: 768px) {\n .membership-splash .content-block {\n font-size: 120%;\n }\n .membership-splash .content-block h1 {\n font-size: 180%;\n }\n}\n@media (min-width: 992px) {\n .membership-splash .content-block {\n font-size: 140%;\n }\n .membership-splash .content-block h1 {\n font-size: 200%;\n }\n}\n.membership-splash.membership-splash-default .content-block {\n max-width: 480px;\n}\n.membership-splash.membership-splash-user .content-block {\n max-width: 720px;\n}\n.membership-splash .visual-cell {\n background-image: url(\"/static/images/splash/membership/dds-painting.png\");\n background-position: center;\n background-repeat: no-repeat;\n background-size: contain;\n min-height: 320px;\n align-self: flex-start;\n}\n@media (max-width: 992px) {\n .membership-splash .visual-cell {\n display: none;\n }\n}\n.membership-splash a:not(.btn) {\n color: #fff;\n transition: all 250ms;\n text-decoration-thickness: 2px;\n text-decoration-line: underline;\n opacity: 0.8;\n}\n.membership-splash a:not(.btn):hover {\n opacity: 1;\n}\n\n/**\n * @module events-list-table.scss\n * @changed 2024.03.21, 16:50\n */\n.events-list-table {\n /*\n .col-registration\n .col-event\n .col-participants\n .col-opens\n .col-closes\n .col-payment\n .col-options\n .col-paid\n .col-actions\n */\n}\n.events-list-table .col-actions,\n.events-list-table .col-payment,\n.events-list-table .col-registration,\n.events-list-table .col-participants,\n.events-list-table .col-paid {\n text-align: center;\n}\n.events-list-table tbody th,\n.events-list-table tbody td {\n vertical-align: middle;\n}\n.events-list-table tbody .col-event {\n color: #486;\n}\n.events-list-table tbody .col-actions-wrapper {\n display: flex;\n gap: 4px;\n justify-content: center;\n flex-wrap: wrap;\n}\n\n/**\n * @module events-list.scss\n * @changed 2024.03.18, 00:57\n */\n.events-list-block {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.events-list-block .events-list-item {\n padding: 16px;\n border-radius: 8px;\n}\n.events-list-block .events-list-item.has-registration {\n background-color: rgba(136, 170, 153, 0.25);\n}\n.events-list-block .events-list-item > * {\n margin-bottom: 0.5rem;\n}\n.events-list-block .events-list-item-title {\n color: #486;\n font-weight: 400;\n}\n.events-list-block .events-list-item-details {\n display: flex;\n flex-wrap: wrap;\n gap: 0.1rem 1rem;\n}","@use 'sass:map';\n@use 'sass:math';\n@use 'sass:color';\n\n@import '../../vendor/bootstrap-5.3.2/scss/functions';\n@import '../../vendor/bootstrap-5.3.2/scss/variables';\n\n// Font...\n\n$defaultFontSize: 14px;\n\n$defaultFontFamily: 'Roboto', 'Helvetica', 'Arial', sans-serif;\n// $defaultFontFamily: Roboto, system-ui, -apple-system, \"Segoe UI\", \"Helvetica Neue\", \"Noto Sans\", \"Liberation Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n\n// Breakpoints:...\n\n// Breakpoints list, according to `static/bootstrap-5.3.2-src/scss/_variables.scss`:\n// - xs: 0\n// - sm: 576px\n// - md: 768px\n// - lg: 992px\n// - xl: 1200px\n// - xxl: 1400px\n\n$screenXsMin: map.get($grid-breakpoints, 'xs'); // 0\n$screenSmMin: map.get($grid-breakpoints, 'sm'); // 576px\n$screenMdMin: map.get($grid-breakpoints, 'md'); // 768px\n$screenLgMin: map.get($grid-breakpoints, 'lg'); // 992px\n$screenXlMin: map.get($grid-breakpoints, 'xl'); // 1200px\n$screenXxlMin: map.get($grid-breakpoints, 'xxl'); // 1400px\n\n$screenXsMax: map.get($grid-breakpoints, 'sm'); // 576px\n$screenSmMax: map.get($grid-breakpoints, 'md'); // 768px\n$screenMdMax: map.get($grid-breakpoints, 'lg'); // 992px\n$screenLgMax: map.get($grid-breakpoints, 'xl'); // 1200px\n$screenXlMax: map.get($grid-breakpoints, 'xxl'); // 1400px\n\n// Collapsable widths...\n\n$collapseWidth: screenMdMin; // $grid-float-breakpoint; // =@screen-sm-min=768px ? =@screen-md-min=992px\n$navbarCollapse: $screenLgMin;\n$navbarCollapseMax: $screenMdMax;\n$midbarCollapse: $collapseWidth;\n\n// Primary color...\n\n$primaryLightColor: #8a9;\n$primaryColor: #486;\n$primaryDarkColor: #375;\n$primaryDarkenColor: color.adjust($primaryDarkColor, $lightness: -10%);\n$primaryDarkestColor: #3c5343;\n\n$primaryColorRgb: 68, 136, 102;\n\n// Misc colors...\n\n// UNUSED?\n$xdarkBlueColor: #036;\n$darkBlueColor: #047;\n$mediumBlueColor: #157;\n$moodBlueColor: #6ac;\n$extralightBlueColor: #def;\n\n$darkGreenColor: #461;\n$mediumGreenColor: #9a0;\n\n$defaultTextColor: #333;\n\n$backgroundColor: #fff;\n\n// Navbar...\n\n$navbarMainHeight: 60px;\n$navbarPlusHeight: 50px;\n\n// Timeouts...\n\n$momentTime: 150ms;\n$transitionTime: 250ms;\n$animationTime: 500ms;\n$effectTime: 1000ms;\n","/**\n * @module forms.scss\n * @changed 2024.03.08, 12:00\n */\n\n@import '../shared';\n\n.asteriskField {\n // crispy_forms element\n display: inline-block;\n margin-left: 4px;\n opacity: 0.5;\n}\n","/**\n * @module customize.scss\n * @changed 2024.03.11, 13:52\n */\n\n@import '../shared';\n\n:root {\n // --bs-body-font-size: #{$defaultFontSize};\n --bs-body-font-family: #{$defaultFontFamily};\n}\n","/**\n * @module body\n * @changed 2024.03.08, 13:30\n */\n\n@import '../shared';\n\n$headerNavbarHeight: 60px;\n\nbody {\n font-family: $defaultFontFamily;\n background-color: $backgroundColor;\n // Add space for fixed navar (see `static/assets/page-header-navbar/page-header-navbar.django`)\n margin-top: $headerNavbarHeight + 20px;\n}\n",".data-form {\n .form-group {\n margin-top: 8px;\n margin-bottom: 8px;\n }\n}\n","/**\n * @module bootstrap-theme-fixes\n * @changed 2024.04.02, 16:21\n */\n\n@use 'sass:color';\n\n@import '../shared';\n\n:root {\n --bs-primary-rgb: #{$primaryColorRgb};\n --bs-link-color-rgb: var(--bs-primary-rgb);\n --bs-link-color: #{$primaryColor}; // #0d6efd;\n // --bs-link-color-rgb: 13, 110, 253;\n // --bs-link-decoration: underline;\n --bs-link-hover-color: #{$primaryDarkenColor}; // #0a58ca;\n --bs-link-hover-color-rgb: var(--bs-link-hover-color);\n // --bs-link-hover-color-rgb: 10, 88, 202;\n // --bs-border-color: #{$primaryColor};\n}\n\n.btn-primary {\n // --bs-btn-color: #fff;\n --bs-btn-bg: #{$primaryColor}; // #0d6efd;\n --bs-btn-border-color: #{$primaryColor}; // #0d6efd;\n // --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #{$primaryDarkColor}; // #0b5ed7;\n --bs-btn-hover-border-color: #{$primaryDarkenColor}; // #0a58ca;\n --bs-btn-focus-shadow-rgb: #{$primaryLightColor}; // #3184fd; // 49, 132, 253;\n // --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #{$primaryDarkenColor}; // #0a58ca;\n --bs-btn-active-border-color: #{$primaryDarkenColor}; // #0a53be;\n // --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n // --bs-btn-disabled-color: #fff;\n --bs-btn-disabled-bg: #{$primaryColor}; // #0d6efd;\n --bs-btn-disabled-border-color: #{$primaryColor}; // #0d6efd;\n}\n\n.btn-outline-primary {\n --bs-btn-color: #{$primaryColor}; // #0d6efd\n --bs-btn-border-color: #{$primaryColor}; // #0d6efd\n // --bs-btn-hover-color: #fff;\n --bs-btn-hover-bg: #{$primaryColor}; // #0d6efd\n --bs-btn-hover-border-color: #{$primaryColor}; // #0d6efd\n --bs-btn-focus-shadow-rgb: #{$primaryColor}; // #0d6efd\n // --bs-btn-active-color: #fff;\n --bs-btn-active-bg: #{$primaryColor}; // #0d6efd\n --bs-btn-active-border-color: #{$primaryColor}; // #0d6efd\n // --bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n --bs-btn-disabled-color: #{$primaryColor}; // #0d6efd\n // --bs-btn-disabled-bg: transparent;\n --bs-btn-disabled-border-color: #{$primaryColor}; // #0d6efd\n // --bs-gradient: none;\n}\n\n// Fix hover styles for combined primary outlined and link buttons\n.btn-outline-primary.btn-link {\n &:active,\n &:hover {\n color: #fff;\n }\n text-decoration: none;\n}\n\n.progress,\n.progress-stacked {\n // --bs-progress-height: 1rem;\n // --bs-progress-font-size: 0.75rem;\n // --bs-progress-bg: var(--bs-secondary-bg);\n // --bs-progress-border-radius: var(--bs-border-radius);\n // --bs-progress-box-shadow: var(--bs-box-shadow-inset);\n // --bs-progress-bar-color: #fff;\n --bs-progress-bar-bg: #{$primaryColor}; // #0d6efd;\n // --bs-progress-bar-transition: width 0.6s ease;\n}\n\n.list-group {\n // --bs-list-group-color: var(--bs-body-color);\n // --bs-list-group-bg: var(--bs-body-bg);\n // --bs-list-group-border-color: var(--bs-border-color);\n // --bs-list-group-border-width: var(--bs-border-width);\n // --bs-list-group-border-radius: var(--bs-border-radius);\n // --bs-list-group-item-padding-x: 1rem;\n // --bs-list-group-item-padding-y: 0.5rem;\n // --bs-list-group-action-color: var(--bs-secondary-color);\n // --bs-list-group-action-hover-color: var(--bs-emphasis-color);\n // --bs-list-group-action-hover-bg: var(--bs-tertiary-bg);\n // --bs-list-group-action-active-color: var(--bs-body-color);\n // --bs-list-group-action-active-bg: var(--bs-secondary-bg);\n // --bs-list-group-disabled-color: var(--bs-secondary-color);\n // --bs-list-group-disabled-bg: var(--bs-body-bg);\n // --bs-list-group-active-color: #fff;\n --bs-list-group-active-bg: #{$primaryColor}; // #0d6efd;\n --bs-list-group-active-border-color: #{$primaryColor}; // #0d6efd;\n}\n\n.btn:focus-visible,\n.btn-check:checked + .btn:focus-visible,\n:not(.btn-check) + .btn:active:focus-visible,\n.btn:first-child:active:focus-visible,\n.btn.active:focus-visible,\n.btn.show:focus-visible,\n.form-check-input:focus,\n.form-select:focus,\n.form-control:focus {\n box-shadow: 0 0 0 0.25rem color.change($primaryLightColor, $alpha: 0.25);\n border-color: $primaryLightColor;\n}\n\n.form-check-input:checked {\n background-color: $primaryColor;\n border-color: $primaryColor;\n}\n\n.table-primary-header {\n thead th {\n background-color: $primaryColor;\n color: #fff;\n }\n th,\n td {\n border-right-width: var(--bs-border-width);\n &:first-child {\n border-left-width: var(--bs-border-width);\n }\n }\n}\n\n.btn-icon {\n padding-left: 0;\n padding-right: 0;\n // For md size:\n width: 38px;\n height: 38px;\n &,\n & > i {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n }\n}\n","/**\n * @module page-header-navbar.scss\n * @changed 2024.03.08, 12:00\n */\n\n@import '../shared';\n\n.page-header-navbar {\n padding: 0;\n // Adaptive layout: trim too long title string with an ellipsis...\n .main-bar {\n flex: 1;\n display: flex;\n width: 100%;\n align-items: center;\n }\n .navbar-brand {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n // Dark primary navbar with background decor...\n &.navbar-dark.navbar-primary {\n @include themeBackgroundBefore;\n }\n .dropdown-menu#user-menu {\n // Position dropdown popup relative to the right screen side (as the menu is positioned to the right)\n right: 0;\n left: auto;\n }\n @media (max-width: 400px) {\n .site-name {\n display: none;\n }\n }\n @media (min-width: $navbarCollapse) {\n .navbar-brand {\n flex: 1;\n }\n .collapse.navbar-collapse {\n flex: 0;\n }\n }\n .nav-link {\n white-space: nowrap;\n color: #fff;\n transition: all $transitionTime;\n opacity: 0.85;\n &:hover {\n opacity: 1;\n }\n }\n}\n","@mixin themeBackground {\n background-image: url('/static/images/splash/curves-bg/curves-x.svg');\n background-position: center top;\n background-repeat: no-repeat;\n background-size: cover;\n}\n@mixin themeBackgroundBaseBefore {\n &:before {\n display: block;\n content: ' ';\n position: absolute;\n top: 0;\n bottom: 0;\n right: 0;\n left: 0;\n opacity: 0.05;\n @include themeBackground;\n }\n .container-fluid {\n z-index: 1;\n }\n}\n@mixin themeBackgroundBefore {\n background-color: $primaryDarkColor;\n color: #fff;\n @include themeBackgroundBaseBefore;\n}\n","/**\n * @module page-footer-navbar\n * @changed 2024.03.08, 13:30\n */\n\n.page-footer-navbar {\n $borderColor: #eee;\n border-top: 1px solid $borderColor;\n font-size: 90%;\n // border-bottom: 1px solid $borderColor;\n margin-bottom: 0;\n margin-top: 20px;\n padding: 0;\n .container-fluid {\n display: flex;\n flex-direction: column;\n flex-wrap: wrap;\n align-content: center;\n align-items: center;\n justify-content: space-between;\n .navbar-right {\n display: flex;\n flex-wrap: wrap;\n }\n @media (min-width: $screenSmMin) {\n flex-direction: row;\n .navbar-copyright,\n .navbar-middle,\n .navbar-right {\n flex: 1;\n }\n .navbar-copyright {\n }\n .navbar-middle {\n }\n .navbar-right {\n justify-content: flex-end;\n }\n }\n }\n .navbar-copyright {\n display: flex;\n align-items: center;\n // gap: 10px;\n }\n .navbar-nav {\n margin: 0;\n flex-direction: row;\n .nav-link {\n padding-right: var(--bs-navbar-nav-link-padding-x);\n padding-left: var(--bs-navbar-nav-link-padding-x);\n }\n }\n}\n","/**\n * @module main-page-splash\n * @changed 2024.03.08, 17:06\n */\n\n@import '../shared';\n\n.main-page-splash {\n @include themeBackgroundBefore;\n position: relative;\n > .content {\n h1 {\n font-weight: 400;\n }\n position: relative;\n }\n}\n","/**\n * @module membership-splash\n * @changed 2024.03.08, 17:06\n */\n\n@use 'sass:color';\n\n@import '../shared';\n\n.membership-splash {\n overflow: hidden;\n position: relative;\n padding: 12px;\n // Theming...\n &.dark {\n @include themeBackgroundBefore;\n }\n &.light {\n background-color: color.change($primaryLightColor, $alpha: 0.1);\n @include themeBackgroundBaseBefore;\n }\n // Ensure z-index for content...\n > .content {\n position: relative;\n }\n .content-cell {\n // text-align: center;\n display: flex;\n align-items: center;\n justify-content: center;\n flex: 2;\n }\n .content-block {\n padding-top: 1em;\n h1 {\n font-weight: 300;\n }\n @media (min-width: $screenMdMin) {\n font-size: 120%;\n h1 {\n font-size: 180%;\n }\n }\n @media (min-width: $screenLgMin) {\n font-size: 140%;\n h1 {\n font-size: 200%;\n }\n }\n }\n &.membership-splash-default .content-block {\n max-width: 480px;\n }\n &.membership-splash-user .content-block {\n max-width: 720px;\n }\n .visual-cell {\n @media (max-width: $screenMdMax) {\n // Hide on small screens\n display: none;\n }\n background-image: url('/static/images/splash/membership/dds-painting.png');\n background-position: center;\n background-repeat: no-repeat;\n background-size: contain;\n min-height: 320px;\n align-self: flex-start;\n }\n a:not(.btn) {\n color: #fff;\n transition: all $transitionTime;\n text-decoration-thickness: 2px;\n text-decoration-line: underline;\n opacity: 0.8;\n &:hover {\n opacity: 1;\n }\n }\n}\n","/**\n * @module events-list-table.scss\n * @changed 2024.03.21, 16:50\n */\n\n@import '../shared';\n\n.events-list-table {\n /*\n .col-registration\n .col-event\n .col-participants\n .col-opens\n .col-closes\n .col-payment\n .col-options\n .col-paid\n .col-actions\n */\n\n .col-actions,\n .col-payment,\n .col-registration,\n .col-participants,\n .col-paid {\n text-align: center;\n }\n\n tbody {\n th,\n td {\n vertical-align: middle;\n }\n .col-event {\n color: $primaryColor;\n }\n .col-actions-wrapper {\n display: flex;\n gap: 4px;\n justify-content: center;\n flex-wrap: wrap;\n }\n }\n}\n","/**\n * @module events-list.scss\n * @changed 2024.03.18, 00:57\n */\n\n@use 'sass:color';\n\n@import '../shared';\n\n.events-list-block {\n display: flex;\n flex-direction: column;\n gap: 8px;\n .events-list-item {\n padding: 16px;\n border-radius: 8px;\n &.has-registration {\n background-color: color.change($primaryLightColor, $alpha: 0.25);\n }\n & > * {\n margin-bottom: 0.5rem;\n }\n }\n .events-list-item-title {\n color: $primaryColor;\n font-weight: 400;\n }\n .events-list-item-details {\n display: flex;\n flex-wrap: wrap;\n gap: 0.1rem 1rem;\n }\n}\n"]} \ No newline at end of file From e719fb2469c6017fd844f2b80f569ba774ba946f Mon Sep 17 00:00:00 2001 From: lilliputten Date: Wed, 10 Apr 2024 19:59:00 +0700 Subject: [PATCH 6/8] Issue #149: Fixed found errors in sending messages for a registration invoice event. Cleaned up code. --- dds_registration/core/helpers/emails.py | 9 ++++++-- dds_registration/models.py | 22 ++++++------------- .../emails/invoice_membership.txt.django | 2 +- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/dds_registration/core/helpers/emails.py b/dds_registration/core/helpers/emails.py index 1bd98ce4..facc720c 100644 --- a/dds_registration/core/helpers/emails.py +++ b/dds_registration/core/helpers/emails.py @@ -5,7 +5,7 @@ def prepare_email_message_text(text: str) -> str: # Remove spaces around text = text.strip() # Remove spaces before newlines - text = re.sub(r"\s*[\n\r]", "\n", text) + text = re.sub(r"[ \t]*[\n\r]", "\n", text) # Leave max two newlines in a row text = re.sub(r"\n{3,}", "\n\n", text) return text @@ -17,7 +17,12 @@ def parse_email_subject_and_content(text: str) -> list[str]: Returns the list consisted of [subject, content] """ text = prepare_email_message_text(text) - return text.split('\n\n', 1) + results = text.split("\n\n", 1) + if len(results) < 2: + raise Exception( + "Email message should constist of a subject and a content, separated from the content by double newline." + ) + return results __all__ = [ diff --git a/dds_registration/models.py b/dds_registration/models.py index 35ecc3cc..5b37158f 100644 --- a/dds_registration/models.py +++ b/dds_registration/models.py @@ -292,28 +292,20 @@ def receipt_pdf(self): def email_invoice(self, request: HttpRequest): user = User.objects.get(id=self.data["user"]["id"]) - # TODO: Issue #149: To extract these (and all other hardcoded here, in `send_email` methods?) texts to template files, with substiting names, urls and emails from settings or preferences values? - scheme = "https" if self.request.is_secure() else "http" + scheme = "https" if request.is_secure() else "http" site = Site.objects.get_current() context = { - "site": site, - "scheme": scheme, - "payment": self, - "user": user, + "site": site, + "scheme": scheme, + "payment": self, + "user": user, } if self.data["kind"] == "membership": email_template = "dds_registration/payment/emails/invoice_membership.txt.django" - # text = f""" - # DdS Membership Invoice {self.invoice_no} - # Thanks for signing up for Départ de Sentier membership! Membership fees allow us to write awesome open source code, deploy open infrastructure, and run community events without spending all our time fundraising.\n\nYour membership will run until December 31st, {user.membership.until} (Don't worry, you will get a reminder to renew for another year :).\n\nPlease find attached the membership invoice. Your membership is not in force until the bank transfer is received.\n\nYou can change your invoice details here: https://events.d-d-s.ch{reverse('membership_application')}.\n\nIf you have any questions, please contact events@d-d-s.ch. - # """ - # subject = f"DdS Membership Invoice {self.invoice_no}" - # message = f"Thanks for signing up for Départ de Sentier membership! Membership fees allow us to write awesome open source code, deploy open infrastructure, and run community events without spending all our time fundraising.\n\nYour membership will run until December 31st, {user.membership.until} (Don't worry, you will get a reminder to renew for another year :).\n\nPlease find attached the membership invoice. Your membership is not in force until the bank transfer is received.\n\nYou can change your invoice details here: https://events.d-d-s.ch{reverse('membership_application')}.\n\nIf you have any questions, please contact events@d-d-s.ch." else: - event = context["event"] = Event.objects.get(id=self.data["event"]["id"]) + context["event"] = Event.objects.get(id=self.data["event"]["id"]) email_template = "dds_registration/payment/emails/invoice_membership.txt.django" - # subject = f"DdS Event {event.title} Registration Invoice {self.invoice_no}" - # message = f"Thanks for registering for {event.title}! We look forward to seeing your, in person or virtually.\n\nDépart de Sentier runs its events and schools on a cost-neutral basis - i.e. we don't make a profit off the registration fees. They are used for catering, room, hotel, and equipment rental, AV hosting and technician fees, and guest speaker costs. We literally could not run this event without your support.\n\nYou can view your registration status and apply for membership at https://events.d-d-s.ch/profile.\n\nPlease find attached the registration invoice. Your registration is not finalized until the bank transfer is received.\n\nYou can change your invoice details here: https://events.d-d-s.ch{reverse('event_registration', args=(event.code,))}.\n\nIf you have any questions, please contact events@d-d-s.ch." + # Parse email message template text = render_to_string( template_name=email_template, context=context, diff --git a/dds_registration/templates/dds_registration/payment/emails/invoice_membership.txt.django b/dds_registration/templates/dds_registration/payment/emails/invoice_membership.txt.django index 7d573311..1a305607 100644 --- a/dds_registration/templates/dds_registration/payment/emails/invoice_membership.txt.django +++ b/dds_registration/templates/dds_registration/payment/emails/invoice_membership.txt.django @@ -9,6 +9,6 @@ Your membership will run until December 31st, {{ user.membership.until }} (Don't Please find attached the membership invoice. Your membership is not in force until the bank transfer is received. -You can change your invoice details here: {{ scheme }}://{{ site.domain }}{{ % url 'membership_application' % }}. +You can change your invoice details here: {{ scheme }}://{{ site.domain }}{% url 'membership_application' %}. If you have any questions, please contact {{ settings.DEFAULT_CONTACT_EMAIL }}. From c2badf468597f3c4e4443131627879905e69d989 Mon Sep 17 00:00:00 2001 From: lilliputten Date: Wed, 10 Apr 2024 17:10:33 +0700 Subject: [PATCH 7/8] Issue #152: Minor linter fixes. --- dds_registration/core/helpers/create_pdf.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/dds_registration/core/helpers/create_pdf.py b/dds_registration/core/helpers/create_pdf.py index ae026bd3..a3b31596 100644 --- a/dds_registration/core/helpers/create_pdf.py +++ b/dds_registration/core/helpers/create_pdf.py @@ -32,7 +32,7 @@ def normalize_text(text: str) -> str: - return text.encode('utf-8', 'ignore').decode('utf-8').strip() + return text.encode("utf-8", "ignore").decode("utf-8").strip() def create_pdf( @@ -87,11 +87,18 @@ def create_pdf( # Left (client) address column... pdf.set_xy(left_column_pos, margin_size + top_offset) - pdf.multi_cell(text=normalize_text(client_name), w=left_column_width, align=Align.L, new_x="LEFT", new_y="NEXT", h=line_height) + pdf.multi_cell( + text=normalize_text(client_name), w=left_column_width, align=Align.L, new_x="LEFT", new_y="NEXT", h=line_height + ) pdf.set_y(pdf.get_y() + small_vertical_space) pdf.multi_cell( - text=normalize_text(client_address), w=left_column_width, align=Align.L, new_x="LEFT", new_y="NEXT", h=line_height + text=normalize_text(client_address), + w=left_column_width, + align=Align.L, + new_x="LEFT", + new_y="NEXT", + h=line_height, ) left_stop_pos = pdf.get_y() From 5becad6a7d630414203cd820add85b4ea70e249c Mon Sep 17 00:00:00 2001 From: lilliputten Date: Wed, 10 Apr 2024 20:18:27 +0700 Subject: [PATCH 8/8] Issue #149: Added template for sending receipt. --- dds_registration/models.py | 27 ++++++++++++++----- .../payment/emails/invoice_event.txt.django | 2 +- .../payment/emails/receipt.txt.django | 12 +++++++++ 3 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 dds_registration/templates/dds_registration/payment/emails/receipt.txt.django diff --git a/dds_registration/models.py b/dds_registration/models.py index 5b37158f..8a73cddd 100644 --- a/dds_registration/models.py +++ b/dds_registration/models.py @@ -292,11 +292,9 @@ def receipt_pdf(self): def email_invoice(self, request: HttpRequest): user = User.objects.get(id=self.data["user"]["id"]) - scheme = "https" if request.is_secure() else "http" - site = Site.objects.get_current() context = { - "site": site, - "scheme": scheme, + "site": Site.objects.get_current(), + "scheme": "https" if request.is_secure() else "http", "payment": self, "user": user, } @@ -322,10 +320,25 @@ def email_invoice(self, request: HttpRequest): def email_receipt(self, request: HttpRequest): user = User.objects.get(id=self.data["user"]["id"]) - kind = "Membership" if self.data["kind"] == "membership" else "Event" + context = { + "kind": "Membership" if self.data["kind"] == "membership" else "Event", + "site": Site.objects.get_current(), + "scheme": "https" if request.is_secure() else "http", + "payment": self, + "user": user, + } + email_template = "dds_registration/payment/emails/receipt.txt.django" + # Parse email message template + text = render_to_string( + template_name=email_template, + context=context, + request=request, + ) + # Extract a subject and a message from the template + [subject, message] = parse_email_subject_and_content(text) user.email_user( - subject=f"DdS {kind} Receipt {self.invoice_no}", - message="Thanks! A receipt for your event or membership payment is attached. You can always find more information about your item at your your profile: https://events.d-d-s.ch/profile.\n\nWe really appreciate your support. If you have any questions, please contact events@d-d-s.ch.", + subject=subject, + message=message, attachment_content=self.receipt_pdf(), attachment_name=f"DdS receipt {self.invoice_no}.pdf", ) diff --git a/dds_registration/templates/dds_registration/payment/emails/invoice_event.txt.django b/dds_registration/templates/dds_registration/payment/emails/invoice_event.txt.django index 8be3c2c8..7c2100b9 100644 --- a/dds_registration/templates/dds_registration/payment/emails/invoice_event.txt.django +++ b/dds_registration/templates/dds_registration/payment/emails/invoice_event.txt.django @@ -5,7 +5,7 @@ Thanks for registering for {{ event.title }}! We look forward to seeing your, in Départ de Sentier runs its events and schools on a cost-neutral basis - i.e. we don't make a profit off the registration fees. They are used for catering, room, hotel, and equipment rental, AV hosting and technician fees, and guest speaker costs. We literally could not run this event without your support. -You can view your registration status and apply for membership at {{ scheme }}://{{ site.domain }}{% url 'profile' %} +You can view your registration status and apply for membership at {{ scheme }}://{{ site.domain }}{% url 'profile' %}. Please find attached the registration invoice. Your registration is not finalized until the bank transfer is received. diff --git a/dds_registration/templates/dds_registration/payment/emails/receipt.txt.django b/dds_registration/templates/dds_registration/payment/emails/receipt.txt.django new file mode 100644 index 00000000..444f0e64 --- /dev/null +++ b/dds_registration/templates/dds_registration/payment/emails/receipt.txt.django @@ -0,0 +1,12 @@ +DdS {{ kind }} Receipt {{ payment.invoice_no }} + + +Thanks! + +A receipt for your event or membership payment is attached. + +You can always find more information about your item at your your profile: {{ scheme }}://{{ site.domain }}{% url 'profile' %}. + +We really appreciate your support. + +If you have any questions, please contact {{ settings.DEFAULT_CONTACT_EMAIL }}.