2027 MD24-L Virtual Duck Race
* { box-sizing: border-box; }
:root {
–lions-blue: #00529b;
–lions-blue-dark: #003d73;
–lions-blue-deep: #062f5d;
–lions-gold: #f5c242;
–lions-gold-dark: #d99a00;
–lions-gold-pale: #fff8dd;
–lions-white: #ffffff;
–lions-light: #f4f7fb;
–lions-mid: #dce4ed;
–lions-text: #30343b;
–shadow-main: 0 18px 46px rgba(0, 61, 115, 0.16);
–shadow-card: 0 9px 24px rgba(0, 61, 115, 0.10);
–card-radius: 17px;
–section-gap: 28px;
}
/* =========================================================
BEGIN: MOBILE BOTTOM BACKGROUND FIX
Keeps the Lions background visible below the WordPress footer
and during mobile Safari overscroll.
========================================================= */
html {
min-height: 100%;
background-color: #d7cf9f;
background:
linear-gradient(180deg, #fffdf5 0%, #eee9c9 48%, #d7cf9f 100%);
}
body {
margin: 0;
padding: 14px;
font-family: Arial, Helvetica, sans-serif;
color: var(–lions-text);
background-color: #d7cf9f;
background:
radial-gradient(circle at top left, rgba(245,194,66,0.28), transparent 30%),
radial-gradient(circle at top right, rgba(0,82,155,0.16), transparent 32%),
linear-gradient(180deg, #fffdf5 0%, #eee9c9 48%, #d7cf9f 100%);
background-attachment: fixed;
}
/* =========================================================
END: MOBILE BOTTOM BACKGROUND FIX
========================================================= */
.duck-container {
width: 100%;
max-width: 960px;
margin: 0 auto;
padding: 24px;
overflow: hidden;
background: var(–lions-white);
border: 4px solid var(–lions-gold);
border-radius: 20px;
box-shadow: var(–shadow-main);
}
img {
max-width: 100%;
height: auto;
}
p {
color: var(–lions-text);
font-size: 16px;
line-height: 1.55;
text-align: center;
}
a {
color: var(–lions-blue-dark);
font-weight: 800;
}
.hero-frame {
overflow: hidden;
border: 4px solid var(–lions-blue);
border-radius: 16px;
background: #fff;
box-shadow: 0 10px 28px rgba(0,82,155,0.18);
}
.hero-frame img {
display: block;
width: 100%;
}
.intro-strip {
margin: 18px 0 0;
padding: 18px 20px;
color: #fff;
text-align: center;
font-size: 20px;
font-weight: 900;
line-height: 1.35;
text-transform: uppercase;
letter-spacing: 0.4px;
border: 3px solid var(–lions-gold);
border-radius: 14px;
background: linear-gradient(135deg, var(–lions-blue) 0%, var(–lions-blue-dark) 100%);
box-shadow: 0 9px 22px rgba(0,82,155,0.16);
}
.section-card {
position: relative;
overflow: hidden;
width: 100%;
margin-top: var(–section-gap);
padding: 30px 28px 28px;
text-align: center;
background: #fff;
border: 2px solid var(–lions-mid);
border-radius: var(–card-radius);
box-shadow: var(–shadow-card);
}
.section-card::before {
content: “”;
position: absolute;
top: 0;
right: 0;
left: 0;
height: 8px;
background: linear-gradient(
90deg,
var(–lions-blue),
var(–lions-gold),
var(–lions-blue)
);
}
.section-card h2,
.section-title {
margin: 6px 0 12px;
color: var(–lions-blue-deep);
font-size: 28px;
font-weight: 900;
line-height: 1.2;
text-align: center;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.purchase-intro {
margin: 0 auto 18px;
max-width: 700px;
font-weight: 700;
}
label {
display: block;
margin-top: 20px;
color: var(–lions-blue-deep);
font-size: 16px;
font-weight: 900;
text-align: left;
}
input[type=”text”],
input[type=”email”] {
width: 100%;
margin-top: 8px;
padding: 15px;
color: #222;
font-size: 16px;
background: #fff;
border: 2px solid #cbd5df;
border-radius: 10px;
}
input[type=”text”]:focus,
input[type=”email”]:focus {
outline: none;
border-color: var(–lions-blue);
box-shadow: 0 0 0 4px rgba(0,82,155,0.14);
}
.checkbox-row {
display: flex;
align-items: center;
gap: 9px;
margin-top: 14px;
font-size: 15px;
}
.char-hint {
margin-top: 5px;
color: #666;
font-size: 13px;
text-align: left;
}
.package-heading {
margin: 26px 0 6px;
color: var(–lions-blue-deep);
font-size: 24px;
font-weight: 900;
text-align: center;
text-transform: uppercase;
letter-spacing: 0.4px;
}
.package-subhead {
margin: 0 auto;
max-width: 680px;
font-weight: 700;
}
.button-group {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 18px;
margin-top: 24px;
align-items: stretch;
}
button {
width: 100%;
cursor: pointer;
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.duck-entry-button {
position: relative;
min-height: 158px;
padding: 25px 14px 18px;
overflow: visible;
color: #fff;
text-align: center;
text-shadow: 0 2px 5px rgba(0,0,0,0.22);
border: 4px solid var(–lions-gold);
border-radius: 18px;
box-shadow:
0 10px 24px rgba(0,0,0,0.16),
inset 0 0 0 1px rgba(255,255,255,0.20);
}
.duck-entry-button.blue {
background: linear-gradient(180deg, #1178d1 0%, var(–lions-blue) 100%);
}
.duck-entry-button.deep {
background: linear-gradient(180deg, #075da7 0%, var(–lions-blue-dark) 100%);
}
.duck-entry-button.gold {
color: var(–lions-blue-deep);
text-shadow: none;
background: linear-gradient(180deg, #ffd768 0%, var(–lions-gold) 100%);
}
.duck-entry-button:hover {
transform: translateY(-3px);
box-shadow: 0 15px 30px rgba(0,0,0,0.22);
}
.featured-button {
z-index: 2;
transform: scale(1.035);
}
.featured-button:hover {
transform: scale(1.035) translateY(-3px);
}
.button-badge {
position: absolute;
top: -16px;
left: 50%;
padding: 7px 15px;
color: var(–lions-blue-deep);
font-size: 12px;
font-weight: 900;
white-space: nowrap;
text-transform: uppercase;
transform: translateX(-50%);
background: var(–lions-gold);
border-radius: 999px;
box-shadow: 0 5px 12px rgba(0,0,0,0.18);
}
.button-top {
display: block;
font-size: 17px;
font-weight: 900;
line-height: 1.15;
text-transform: uppercase;
}
.button-price {
display: block;
margin-top: 8px;
font-size: 48px;
font-weight: 900;
line-height: 1;
}
.button-note {
display: block;
margin-top: 9px;
font-size: 14px;
font-weight: 900;
line-height: 1.2;
}
.note {
margin-top: 20px;
color: #555;
font-size: 14px;
text-align: center;
}
.lcif-credit-note {
margin-top: 20px;
padding: 15px 18px;
color: var(–lions-blue-deep);
font-size: 14px;
font-weight: 800;
line-height: 1.5;
text-align: center;
background: var(–lions-gold-pale);
border-left: 7px solid var(–lions-gold);
border-radius: 12px;
}
.error {
display: none;
margin-top: 15px;
color: #b00020;
font-weight: 900;
text-align: center;
}
.accordion {
margin-top: 16px;
overflow: hidden;
border: 2px solid var(–lions-mid);
border-radius: 13px;
}
.accordion-item {
border-bottom: 1px solid var(–lions-mid);
}
.accordion-item:last-child {
border-bottom: none;
}
.accordion-header {
position: relative;
padding: 17px 46px 17px 18px;
color: var(–lions-blue-deep);
font-size: 16px;
font-weight: 900;
text-align: left;
cursor: pointer;
background: #fff;
border-left: 7px solid var(–lions-gold);
}
.accordion-header::after {
content: “+”;
position: absolute;
top: 50%;
right: 18px;
color: var(–lions-blue);
font-size: 24px;
font-weight: 900;
transform: translateY(-50%);
}
.accordion-header:hover {
background: var(–lions-light);
}
.accordion-content {
max-height: 0;
overflow: hidden;
padding: 0 18px;
color: var(–lions-text);
font-size: 15px;
line-height: 1.6;
text-align: left;
background: var(–lions-light);
opacity: 0;
transition:
max-height 0.32s ease,
padding 0.32s ease,
opacity 0.22s ease;
}
.accordion-content.is-open {
max-height: 700px;
padding: 18px;
opacity: 1;
}
.accordion-header[aria-expanded=”true”]::after {
content: “−”;
}
.accordion-content ul {
margin: 0;
padding-left: 22px;
}
.prize-feature {
margin-top: 18px;
padding: 22px;
background: linear-gradient(180deg, #fff 0%, var(–lions-light) 100%);
border: 3px solid var(–lions-gold);
border-radius: 16px;
}
.prize-ribbon {
margin: -2px 0 18px;
padding: 14px 16px;
color: #fff;
font-size: 21px;
font-weight: 900;
text-align: center;
text-transform: uppercase;
background: linear-gradient(135deg, var(–lions-blue) 0%, var(–lions-blue-dark) 100%);
border: 3px solid var(–lions-gold);
border-radius: 12px;
}
.award-image {
display: block;
width: 100%;
max-width: 500px;
margin: 18px auto 0;
}
.district-prize-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16px;
margin-top: 18px;
}
.district-prize-box {
padding: 22px 14px;
background: var(–lions-light);
border: 2px solid #fff;
border-top: 8px solid var(–lions-gold);
border-radius: 14px;
box-shadow: 0 6px 16px rgba(0,0,0,0.08);
}
.district-prize-box strong {
display: block;
color: var(–lions-blue-deep);
font-size: 18px;
text-transform: uppercase;
}
.district-prize-box span {
display: block;
margin-top: 8px;
color: var(–lions-blue);
font-size: 26px;
font-weight: 900;
}
.lcif-card img {
display: block;
width: 100%;
max-width: 285px;
margin: 10px auto;
}
/* =========================================================
BEGIN: VIRGINIA DISTRICT CHALLENGE SCOREBOARD
Live duck totals for MD24-C, MD24-I, and MD24-L.
MD24-L is subtly highlighted on this page.
========================================================= */
.md24l-district-challenge {
position: relative;
overflow: hidden;
margin-top: 18px;
padding: 26px 24px 22px;
text-align: center;
background: linear-gradient(180deg, #ffffff 0%, #f4f7fb 100%);
border: 3px solid var(–lions-gold);
border-radius: var(–card-radius);
box-shadow: var(–shadow-card);
}
.md24l-district-challenge::before {
content: “”;
position: absolute;
top: 0;
right: 0;
left: 0;
height: 7px;
background: linear-gradient(90deg, var(–lions-blue), var(–lions-gold), var(–lions-blue));
}
.md24l-district-challenge h2 {
margin: 5px 0 8px;
color: var(–lions-blue-deep);
font-size: 29px;
font-weight: 900;
line-height: 1.15;
text-transform: uppercase;
letter-spacing: 0.4px;
}
.md24l-district-challenge-intro {
margin: 0 auto 18px;
max-width: 680px;
color: #555;
font-size: 15px;
font-weight: 700;
}
.md24l-district-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 14px;
}
.md24l-district-card {
padding: 17px 10px 16px;
color: #fff;
background: linear-gradient(135deg, var(–lions-blue) 0%, var(–lions-blue-dark) 100%);
border: 2px solid var(–lions-gold);
border-radius: 14px;
box-shadow: 0 7px 16px rgba(0, 61, 115, 0.12);
}
/* Subtle emphasis for the district page currently being viewed */
.md24l-district-card.is-current {
background: linear-gradient(135deg, #0b68b7 0%, var(–lions-blue-dark) 100%);
border-width: 3px;
box-shadow: 0 8px 19px rgba(0, 61, 115, 0.18);
}
.md24l-district-name {
display: block;
font-size: 16px;
font-weight: 900;
line-height: 1.2;
}
.md24l-district-number {
display: block;
margin-top: 7px;
color: #fff4c2;
font-size: 38px;
font-weight: 900;
line-height: 1;
}
.md24l-district-number.is-loading {
font-size: 16px;
padding: 11px 0;
}
.md24l-district-label {
display: block;
margin-top: 6px;
font-size: 11px;
font-weight: 900;
letter-spacing: 0.8px;
text-transform: uppercase;
}
.md24l-district-challenge-cta {
margin: 18px 0 0;
color: var(–lions-blue-deep);
font-size: 18px;
font-weight: 900;
line-height: 1.3;
}
.md24l-district-updated {
margin-top: 7px;
color: #777;
font-size: 12px;
font-weight: 700;
}
@media (max-width: 600px) {
.md24l-district-challenge {
margin-top: 16px;
padding: 22px 14px 19px;
}
.md24l-district-challenge h2 {
font-size: 24px;
}
.md24l-district-grid {
gap: 8px;
}
.md24l-district-card {
padding: 14px 5px 13px;
}
.md24l-district-name {
font-size: 13px;
}
.md24l-district-number {
font-size: 31px;
}
.md24l-district-label {
font-size: 9px;
letter-spacing: 0.4px;
}
.md24l-district-challenge-cta {
font-size: 16px;
}
}
/* =========================================================
END: VIRGINIA DISTRICT CHALLENGE SCOREBOARD
========================================================= */
/* =========================================================
BEGIN: ARE YOU IN THE RACE? SECTION
Live MD24-L participant activity board.
Displays unique recent participants only.
========================================================= */
.md24l-race-scroller-card {
position: relative;
margin-top: var(–section-gap);
padding: 30px 28px 26px;
overflow: hidden;
text-align: center;
background:
linear-gradient(
135deg,
var(–lions-blue) 0%,
var(–lions-blue-dark) 100%
);
border: 3px solid var(–lions-gold);
border-radius: var(–card-radius);
box-shadow: 0 10px 26px rgba(0,82,155,0.18);
}
.md24l-race-scroller-card h2 {
margin: 0 0 7px;
color: #ffffff;
font-size: 30px;
font-weight: 900;
line-height: 1.15;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.md24l-race-total {
margin-top: 5px;
color: var(–lions-gold);
font-size: 22px;
font-weight: 900;
}
.md24l-race-subtext {
margin-top: 8px;
color: rgba(255,255,255,0.92);
font-size: 14px;
font-weight: 700;
}
/* White scrolling activity window */
.md24l-buyers-wrap {
position: relative;
max-width: 660px;
height: 235px;
margin: 20px auto 0;
padding: 6px 18px;
overflow: hidden;
background: #ffffff;
border: 3px dashed var(–lions-gold);
border-radius: 14px;
box-shadow: inset 0 2px 8px rgba(0,0,0,0.04);
}
/* List that will move upward */
.md24l-buyers-list {
position: relative;
width: 100%;
}
/* Individual participant */
.md24l-buyer-item {
padding: 15px 8px;
text-align: center;
border-bottom: 1px solid #e2e7ec;
animation: md24lParticipantFade 0.5s ease;
}
.md24l-buyer-item:last-child {
border-bottom: none;
}
.md24l-buyer-name {
color: var(–lions-blue-deep);
font-size: 19px;
font-weight: 900;
line-height: 1.25;
}
.md24l-buyer-club {
margin-top: 5px;
color: #555;
font-size: 14px;
font-weight: 700;
line-height: 1.3;
}
/* New records fade gently into view */
@keyframes md24lParticipantFade {
from {
opacity: 0;
transform: translateY(5px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Shown if no participants exist yet */
.md24l-race-empty {
padding: 55px 15px;
color: #555;
font-size: 16px;
font-weight: 700;
text-align: center;
}
/* =========================================================
END: ARE YOU IN THE RACE? SECTION
========================================================= */
.find-ducks-card {
margin-top: var(–section-gap);
padding: 30px 28px;
text-align: center;
background: #fff;
border: 3px solid var(–lions-gold);
border-radius: var(–card-radius);
box-shadow: var(–shadow-card);
}
.find-ducks-card h2 {
margin: 0 0 10px;
color: var(–lions-blue);
font-size: 32px;
font-weight: 900;
}
.find-ducks-card p {
margin: 0 0 18px;
font-weight: 700;
}
.find-ducks-button {
margin-top: 14px;
padding: 16px 18px;
color: #fff;
font-size: 18px;
font-weight: 900;
background: var(–lions-blue);
border: 3px solid var(–lions-gold);
border-radius: 12px;
}
.find-ducks-button:hover {
background: var(–lions-blue-dark);
transform: translateY(-2px);
}
.share-card {
margin-top: var(–section-gap);
padding: 28px 22px;
text-align: center;
background: var(–lions-light);
border: 2px solid var(–lions-mid);
border-radius: 16px;
box-shadow: 0 7px 18px rgba(0,61,115,0.07);
}
.share-card h2 {
margin: 0 0 10px;
color: var(–lions-blue-deep);
font-size: 28px;
font-weight: 900;
text-transform: uppercase;
}
.share-card img {
display: block;
width: 190px;
max-width: 75%;
margin: 18px auto;
background: #fff;
border: 8px solid #fff;
border-radius: 14px;
box-shadow: 0 8px 20px rgba(0,0,0,0.15);
}
.share-link {
font-size: 21px;
word-break: break-word;
}
.lower-cta {
margin: 28px auto 0;
text-align: center;
}
.lower-cta button {
display: inline-block;
width: auto;
max-width: 100%;
padding: 14px 28px;
color: #fff;
font-size: 20px;
font-weight: 900;
text-transform: uppercase;
background: var(–lions-blue-dark);
border: 4px solid var(–lions-gold);
border-radius: 999px;
box-shadow: 0 7px 16px rgba(0,0,0,0.14);
}
.lower-cta button:hover {
background: var(–lions-blue-deep);
transform: translateY(-2px);
}
/* =========================================================
BEGIN: MOBILE STICKY ADOPT BUTTON
Mobile only.
Hidden near the top of the page.
========================================================= */
.md24l-mobile-sticky-adopt{
display:none;
}
@keyframes md24lStickyFade {
from {
opacity: 0;
transform: translateY(18px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* =========================================================
END: MOBILE STICKY ADOPT BUTTON
========================================================= */
/* =========================================================
BEGIN: CONSOLIDATED MOBILE STYLES
One breakpoint for layout, live activity, sticky CTA,
and WordPress footer spacing.
========================================================= */
@media (max-width: 760px) {
html,
body,
#page,
.site,
.site-content,
.content-area,
.site-main,
main,
article,
.entry-content {
height: auto !important;
min-height: 0 !important;
margin-bottom: 0 !important;
padding-bottom: 0 !important;
}
html,
body {
background-color: #d7cf9f;
}
body {
padding: 14px 14px 0;
background-attachment: scroll !important;
}
.duck-container {
padding: 16px;
border-width: 3px;
border-radius: var(–card-radius);
}
.intro-strip {
padding: 15px 12px;
font-size: 17px;
}
.section-card,
.find-ducks-card,
.share-card {
margin-top: 22px;
padding: 23px 17px;
}
.section-card h2,
.section-title,
.share-card h2 {
font-size: 23px;
}
.button-group {
grid-template-columns: 1fr;
gap: 18px;
}
.duck-entry-button {
min-height: 132px;
}
.featured-button,
.featured-button:hover {
transform: none;
}
.district-prize-grid {
grid-template-columns: 1fr;
}
.md24l-race-scroller-card {
margin-top: 22px;
padding: 24px 16px 22px;
}
.md24l-race-scroller-card h2 {
font-size: 25px;
}
.md24l-race-total {
font-size: 19px;
}
.md24l-race-subtext {
font-size: 13px;
}
.md24l-buyers-wrap {
height: 220px;
margin-top: 17px;
padding: 5px 12px;
}
.md24l-buyer-item {
padding: 14px 5px;
}
.md24l-buyer-name {
font-size: 18px;
}
.md24l-buyer-club {
font-size: 13px;
}
.find-ducks-card h2 {
font-size: 26px;
}
.lower-cta button {
width: 100%;
}
.md24l-mobile-sticky-adopt {
position: fixed;
left: 14px;
right: 14px;
bottom: 18px;
z-index: 9999;
display: none;
animation: md24lStickyFade 0.35s ease;
}
.md24l-mobile-sticky-adopt button {
width: 100%;
padding: 16px 20px;
color: #fff;
font-size: 20px;
font-weight: 900;
letter-spacing: 0.4px;
text-transform: uppercase;
background: linear-gradient(180deg, #1178d1 0%, var(–lions-blue-dark) 100%);
border: 4px solid var(–lions-gold);
border-radius: 999px;
box-shadow: 0 10px 28px rgba(0,0,0,0.28);
cursor: pointer;
transition: transform 0.15s, box-shadow 0.15s;
}
.md24l-mobile-sticky-adopt button:active {
transform: scale(0.98);
}
.site-footer,
footer {
margin-bottom: 0 !important;
padding-bottom: 0 !important;
}
}
/* =========================================================
END: CONSOLIDATED MOBILE STYLES
========================================================= */
Choose Your Club • Adopt Your Ducks • Help Lions Change Lives!
Be One Of The First!
See how many ducks each Virginia District has in the 2027 race right now.
MD24-C
Loading…
Ducks
MD24-I
Loading…
Ducks
MD24-L
Loading…
Ducks
Adopt Your Ducks and Help MD24-L Move Ahead!
Loading current district totals…
Choose Your Club
Choose your club, then select how many ducks you would like to adopt.
Scroll down for frequently asked questions and prize information.
Select Your Club
Member Number (Optional)
Not a MD24 Member
Select an Adoption Package
Every adopted duck supports Lions Clubs International Foundation.
Adopt 1 Duck
$5
Duck Adoption
Most Popular
Adopt 5 Ducks
$20
Duck Adoption
Best Value
Adopt 15 Ducks
$50
Duck Adoption
You will be taken to a secure checkout page.
LCIF donation credit will be accrued at the Club and District level.
Funding for the Grand Prize MJF Award will be fairly shared across the districts.
Frequently Asked Questions
Each of Virginia’s three Districts runs its own virtual race.
Ducks race through a fun animated river online.
The top 15 ducks from each District advance to the Championship Race.
One lucky duck wins the Grand Prize at the Championship Race.
Ducks dodging rocks
Racing through rapids
Going over waterfalls
Getting tangled in the brush
Plenty of fun
Grand Prize: Melvin Jones Fellowship
The winner will designate the recipient of a prestigious recognition
honoring exceptional service to Lionism.
District 1st Place Prize — $500 Community Impact Grant
Your Winning Duck Could Make a $500 Difference in Your Community!
The 1st Place winner will have the opportunity to nominate a Lions Club of their choice to receive a $500 Community Impact Grant from Lions Clubs International Foundation (LCIF) .
The winner may also suggest how the grant could make a difference in that community! The selected Lions Club will determine how best to use the funds for an eligible community service project, taking the winner’s suggestion into consideration.
Examples of how your Lions Club could use the $500 grant:
Support Humanitarian Projects: Help fund initiatives that improve community welfare and demonstrate the positive impact of Lions.
Promote Health and Wellness: Support local health initiatives, vision care, screenings, or wellness programs.
Strengthen Community Partnerships: Develop activities that bring Lions together with local organizations to serve community needs.
Win the Race. Choose a Club. Make a Difference!
Grant award and use are subject to LCIF eligibility requirements and approval. No cash prize is awarded directly to the winner.
Saturday, May 29, 2027
Cheer on your ducks in person at the Virginia State Convention—or
from anywhere online. Winners do not need to be present.
Championship Grand Prize
Grand Prize — Championship Race
Sponsored by all three Virginia Districts
The Championship Race includes the top 15 finishers from each of the
three Virginia District races.
Supporting LCIF
100% of Duck Race sales goes to LCIF.
🔍 Find My Ducks
Enter the exact email address used for your online or cash entry.
Find My Ducks
Adopt Ducks Now
Adopt Ducks
const SOURCE_ID = “md24l”;
const clubInput = document.getElementById(“clubInput”);
const memberNumberInput = document.getElementById(“memberNumberInput”);
const notMember = document.getElementById(“notMember”);
const commentWrap = document.getElementById(“commentWrap”);
const commentInput = document.getElementById(“commentInput”);
notMember.addEventListener(“change”, () => {
if (notMember.checked) {
clubInput.value = “”;
clubInput.required = false;
clubInput.style.display = “none”;
commentWrap.style.display = “block”;
commentInput.focus();
} else {
clubInput.required = true;
clubInput.style.display = “block”;
commentWrap.style.display = “none”;
}
});
commentInput.addEventListener(“focus”, () => {
if (commentInput.value === “Comment”) {
commentInput.value = “”;
}
});
async function startCheckout(amount) {
const SALES_CLOSE = new Date(“2027-05-29T12:00:00-04:00”);
if (new Date() >= SALES_CLOSE) {
const errorEl = document.getElementById(“error”);
errorEl.innerHTML = `
Sales Closed –
Click Here
`;
errorEl.style.display = “block”;
return;
}
const errorEl = document.getElementById(“error”);
errorEl.style.display = “none”;
let club = “”;
let comment = “”;
let memberNumber = memberNumberInput.value.trim();
if (notMember.checked) {
club = “Not a MD24 Member”;
comment = commentInput.value.trim();
} else {
club = clubInput.value.trim();
if (!club) {
errorEl.textContent = “Please select a Club or check Not a MD24 Member.”;
errorEl.style.display = “block”;
return;
}
}
try {
const response = await fetch(
“https://express-js-on-vercel-three-flame-59.vercel.app/api/checkout”,
{
method: “POST”,
headers: { “Content-Type”: “application/json” },
body: JSON.stringify({
amount,
club,
comment,
memberNumber,
source: SOURCE_ID
})
}
);
const data = await response.json();
if (!data.url) throw new Error();
window.location.href = data.url;
} catch {
errorEl.textContent = “Error starting checkout. Please try again.”;
errorEl.style.display = “block”;
}
}
const MD24L_APPS_SCRIPT_URL =
“https://script.google.com/macros/s/AKfycbz8zJ5KCHfXbMHf1FdG5qNvMEvhO9W6ATbeBjftg6a0Kzou4s_Ke7IEigrv0zvD7HfL/exec”;
function requestMD24LPublicData(parameters, callbackName, handler) {
const oldScript =
document.getElementById(callbackName + “Script”);
if (oldScript) {
oldScript.remove();
}
window[callbackName] = function(data) {
try {
handler(data);
} finally {
const scriptToRemove =
document.getElementById(callbackName + “Script”);
if (scriptToRemove) {
scriptToRemove.remove();
}
try {
delete window[callbackName];
} catch (e) {
window[callbackName] = undefined;
}
}
};
const url = new URL(MD24L_APPS_SCRIPT_URL);
url.searchParams.set(“action”, “lookup”);
url.searchParams.set(“callback”, callbackName);
url.searchParams.set(“cache”, Date.now());
Object.keys(parameters || {}).forEach(function(key) {
url.searchParams.set(key, parameters[key]);
});
const script = document.createElement(“script”);
script.id = callbackName + “Script”;
script.src = url.toString();
script.onerror = function() {
handler({
success: false,
error: “Request failed”
});
};
document.body.appendChild(script);
}
function lookupMD24LDucks() {
const inputEl =
document.getElementById(“md24lDuckLookupInput”);
const resultsEl =
document.getElementById(“md24lDuckLookupResults”);
if (!inputEl || !resultsEl) return;
const email = inputEl.value.trim().toLowerCase();
if (!/^S+@S+.S+$/.test(email)) {
resultsEl.innerHTML = `
Please enter a complete email address.
`;
inputEl.focus();
return;
}
resultsEl.innerHTML = `
Searching for your ducks…
Checking the official MD24-L race list.
`;
requestMD24LPublicData(
{ email: email },
“receiveMD24LLookup_” + Date.now(),
function(data) {
if (!data || data.success !== true) {
resultsEl.innerHTML = `
Duck lookup is temporarily unavailable.
`;
return;
}
const results = Array.isArray(data.results)
? data.results
: [];
if (!results.length) {
resultsEl.innerHTML = `
No ducks were found for that exact email address yet.
`;
return;
}
const grouped = {};
results.forEach(function(item) {
const displayName =
item.displayName || “Duck Race Entry”;
const club =
item.club || “Not Provided”;
const district =
item.district || “MD24-L”;
const key =
displayName + “||” + club + “||” + district;
if (!grouped[key]) {
grouped[key] = {
displayName: displayName,
club: club,
district: district,
duckNumbers: []
};
}
grouped[key].duckNumbers.push(
Number(item.duckNumber)
);
});
resultsEl.innerHTML =
Object.keys(grouped).map(function(key) {
const item = grouped[key];
const ranges =
formatMD24LDuckRanges(item.duckNumbers);
return `
${escapeMD24LHtml(item.displayName)}
District:
${escapeMD24LHtml(item.district)}
Club:
${escapeMD24LHtml(item.club)}
${item.duckNumbers.length === 1 ? “Duck Number:” : “Duck Numbers:”}
${escapeMD24LHtml(ranges)}
(${item.duckNumbers.length}
${item.duckNumbers.length === 1 ? “Duck” : “Ducks”})
`;
}).join(“”);
}
);
}
function formatMD24LDuckRanges(numbers) {
const cleanNumbers = numbers
.filter(function(number) {
return !isNaN(number);
})
.sort(function(a, b) {
return a – b;
});
if (!cleanNumbers.length) return “”;
const ranges = [];
let start = cleanNumbers[0];
let end = cleanNumbers[0];
for (let i = 1; i < cleanNumbers.length; i++) {
if (cleanNumbers[i] === end + 1) {
end = cleanNumbers[i];
} else {
ranges.push(
start === end
? String(start)
: String(start) + "–" + String(end)
);
start = cleanNumbers[i];
end = cleanNumbers[i];
}
}
ranges.push(
start === end
? String(start)
: String(start) + "–" + String(end)
);
return ranges.join(", ");
}
function escapeMD24LHtml(value) {
return String(value || "")
.replace(/&/g, "&")
.replace(//g, “>”)
.replace(/”/g, “"”)
.replace(/’/g, “'”);
}
(function () {
const DISTRICT_TOTALS_STORAGE_KEY =
“virginiaDistrictDuckTotals2027”;
const DISTRICT_TOTALS_MAX_AGE =
10 * 60 * 1000; // 10 minutes
let districtTotalsStarted = false;
let districtTotalsRefreshTimer = null;
function setDistrictTotal(elementId, value) {
const element = document.getElementById(elementId);
if (!element) return;
element.classList.remove(“is-loading”);
element.textContent =
Number(value || 0).toLocaleString();
}
function displayDistrictTotals(data) {
if (!data || !data.districts) return false;
setDistrictTotal(
“md24cDuckTotal”,
data.districts[“MD24-C”]
);
setDistrictTotal(
“md24iDuckTotal”,
data.districts[“MD24-I”]
);
setDistrictTotal(
“md24lDistrictDuckTotal”,
data.districts[“MD24-L”]
);
return true;
}
function saveDistrictTotals(data) {
try {
localStorage.setItem(
DISTRICT_TOTALS_STORAGE_KEY,
JSON.stringify({
districts: data.districts,
updated: data.updated || new Date().toISOString(),
savedAt: Date.now()
})
);
} catch (error) {
// Storage may be unavailable in some privacy modes.
// The live request still works normally.
}
}
function loadSavedDistrictTotals() {
try {
const saved =
localStorage.getItem(
DISTRICT_TOTALS_STORAGE_KEY
);
if (!saved) return false;
const data = JSON.parse(saved);
if (
!data ||
!data.districts ||
!data.savedAt
) {
return false;
}
const age =
Date.now() – Number(data.savedAt);
if (age > DISTRICT_TOTALS_MAX_AGE) {
localStorage.removeItem(
DISTRICT_TOTALS_STORAGE_KEY
);
return false;
}
return displayDistrictTotals(data);
} catch (error) {
return false;
}
}
function loadMD24DistrictTotals() {
const updatedEl =
document.getElementById(
“md24lDistrictUpdated”
);
const oldScript =
document.getElementById(
“md24lDistrictTotalsScript”
);
if (oldScript) oldScript.remove();
const callbackName =
“receiveMD24DistrictTotals_” +
Date.now();
window[callbackName] = function (data) {
try {
if (
!data ||
data.success !== true ||
!data.districts
) {
throw new Error(
“Invalid district totals response”
);
}
displayDistrictTotals(data);
saveDistrictTotals(data);
if (updatedEl) {
updatedEl.textContent =
“Totals update automatically every five minutes.”;
}
} catch (error) {
if (updatedEl) {
updatedEl.textContent =
“Current district totals are temporarily unavailable.”;
}
} finally {
const scriptToRemove =
document.getElementById(
“md24lDistrictTotalsScript”
);
if (scriptToRemove) {
scriptToRemove.remove();
}
try {
delete window[callbackName];
} catch (e) {
window[callbackName] = undefined;
}
}
};
const url =
new URL(MD24L_APPS_SCRIPT_URL);
url.searchParams.set(
“action”,
“districtTotals”
);
url.searchParams.set(
“callback”,
callbackName
);
// One URL cache version per five-minute window.
url.searchParams.set(
“cache”,
Math.floor(Date.now() / 300000)
);
const script =
document.createElement(“script”);
script.id =
“md24lDistrictTotalsScript”;
script.src =
url.toString();
script.onerror = function () {
if (updatedEl) {
updatedEl.textContent =
“Current district totals are temporarily unavailable.”;
}
try {
delete window[callbackName];
} catch (e) {
window[callbackName] = undefined;
}
};
document.body.appendChild(script);
}
function startMD24DistrictTotals() {
if (districtTotalsStarted) return;
districtTotalsStarted = true;
const updatedEl =
document.getElementById(
“md24lDistrictUpdated”
);
if (updatedEl) {
updatedEl.textContent =
“Checking current district totals…”;
}
loadMD24DistrictTotals();
districtTotalsRefreshTimer = window.setInterval(
loadMD24DistrictTotals,
300000
);
}
// Show recent browser-saved totals immediately if available.
const hadSavedTotals =
loadSavedDistrictTotals();
const updatedEl =
document.getElementById(
“md24lDistrictUpdated”
);
if (hadSavedTotals && updatedEl) {
updatedEl.textContent =
“Showing recent totals — live update will load when this section is viewed.”;
} else if (updatedEl) {
updatedEl.textContent =
“Current totals will load when this section is viewed.”;
}
// PERFORMANCE / MOBILE CHECKOUT FIX:
// Do not call Apps Script during initial page load.
// Start only when the scoreboard approaches the viewport.
const challengeSection =
document.querySelector(
“.md24l-district-challenge”
);
if (
!challengeSection ||
!(“IntersectionObserver” in window)
) {
// Fallback for older browsers:
// delay instead of running immediately.
window.setTimeout(
startMD24DistrictTotals,
2500
);
return;
}
const observer =
new IntersectionObserver(
function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
startMD24DistrictTotals();
observer.disconnect();
}
});
},
{
root: null,
rootMargin: “250px 0px”,
threshold: 0
}
);
observer.observe(challengeSection);
})();
const MD24L_RACEDAY_URL =
MD24L_APPS_SCRIPT_URL + “?raceday=1”;
let md24lScrollTimer = null;
let md24lScrollResetTimer = null;
/* ———————————————————
Escape text before placing it into HTML
——————————————————— */
function escapeMD24LRaceHtml(value) {
return String(value || “”)
.replace(/&/g, “&”)
.replace(//g, “>”)
.replace(/”/g, “"”)
.replace(/’/g, “'”);
}
/* ———————————————————
Normalize club wording for cleaner display
——————————————————— */
function formatMD24LClubName(value) {
let club = String(value || “”).trim();
if (!club) {
return “Club not listed”;
}
if (
club.toLowerCase() === “not a member” ||
club.toLowerCase() === “not a md24 member”
) {
return “Not a MD24 Member”;
}
return club;
}
/* ———————————————————
Stop any previous scrolling animation
——————————————————— */
function stopMD24LScroller() {
if (md24lScrollTimer) {
clearInterval(md24lScrollTimer);
md24lScrollTimer = null;
}
if (md24lScrollResetTimer) {
clearTimeout(md24lScrollResetTimer);
md24lScrollResetTimer = null;
}
}
/* ———————————————————
Start smooth upward scrolling only when needed
——————————————————— */
function startMD24LScroller() {
stopMD24LScroller();
const wrap =
document.querySelector(“.md24l-buyers-wrap”);
const list =
document.getElementById(“md24lBuyersList”);
if (!wrap || !list) return;
/* If everything fits, keep the list still */
if (list.scrollHeight =
list.scrollHeight – 2;
if (reachedBottom) {
clearInterval(md24lScrollTimer);
md24lScrollTimer = null;
md24lScrollResetTimer =
setTimeout(function() {
wrap.scrollTo({
top: 0,
behavior: “smooth”
});
md24lScrollResetTimer =
setTimeout(function() {
startMD24LScroller();
}, 1200);
}, 1800);
}
}, 45);
}
/* ———————————————————
Load current MD24-L race activity
——————————————————— */
async function loadMD24LRaceDay() {
const totalEl =
document.getElementById(“md24lTotalDucks”);
const listEl =
document.getElementById(“md24lBuyersList”);
if (!totalEl || !listEl) return;
try {
const response =
await fetch(
MD24L_RACEDAY_URL +
“&cache=” +
Date.now()
);
if (!response.ok) {
throw new Error(“Race data request failed”);
}
const data =
await response.json();
const totalDucks =
Number(data.totalDuckRows || 0);
/* Correct singular/plural wording */
totalEl.textContent =
totalDucks +
” ” +
(totalDucks === 1 ? “Duck Adopted” : “Ducks Adopted”);
const rawBuyers =
Array.isArray(data.buyers)
? data.buyers
: [];
/*
Build unique participant list.
A person may own multiple ducks. We only want that
participant displayed once for each distinct
name + club combination.
*/
const uniqueBuyers = [];
const seen = new Set();
rawBuyers
.slice()
.reverse()
.forEach(function(buyer) {
const displayName =
String(
buyer.displayName ||
“Duck Race Participant”
).trim();
const club =
formatMD24LClubName(
buyer.club
);
const key =
displayName.toLowerCase() +
“||” +
club.toLowerCase();
if (seen.has(key)) {
return;
}
seen.add(key);
uniqueBuyers.push({
displayName: displayName,
club: club
});
});
/*
Show only the 30 most recent unique participants.
No duplicate filler entries are created.
*/
const recentBuyers =
uniqueBuyers.slice(0, 30);
if (!recentBuyers.length) {
stopMD24LScroller();
listEl.innerHTML = `
Be among the first to adopt a duck!
`;
return;
}
listEl.innerHTML =
recentBuyers
.map(function(buyer) {
return `
${escapeMD24LRaceHtml(
buyer.displayName
)}
${escapeMD24LRaceHtml(
buyer.club
)}
`;
})
.join(“”);
/*
Give the browser a moment to render the list,
then decide whether scrolling is necessary.
*/
setTimeout(
startMD24LScroller,
300
);
} catch (err) {
stopMD24LScroller();
listEl.innerHTML = `
Race activity is temporarily unavailable.
`;
}
}
/* ———————————————————
PERFORMANCE:
Delay the first Race Activity request until this lower
section is approaching the visitor’s screen.
——————————————————— */
(function () {
const raceSection =
document.querySelector(“.md24l-race-scroller-card”);
let hasStarted = false;
let refreshTimer = null;
function startRaceActivity() {
if (hasStarted) return;
hasStarted = true;
loadMD24LRaceDay();
refreshTimer = setInterval(
loadMD24LRaceDay,
60000
);
}
if (!raceSection || !(“IntersectionObserver” in window)) {
startRaceActivity();
return;
}
const observer = new IntersectionObserver(
function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
startRaceActivity();
observer.disconnect();
}
});
},
{
root: null,
rootMargin: “700px 0px”,
threshold: 0
}
);
observer.observe(raceSection);
})();
(function () {
const headers = document.querySelectorAll(“.accordion-header”);
function toggleAccordion(header) {
const content = header.nextElementSibling;
if (!content || !content.classList.contains(“accordion-content”)) return;
const isOpen = header.getAttribute(“aria-expanded”) === “true”;
header.setAttribute(“aria-expanded”, String(!isOpen));
content.classList.toggle(“is-open”, !isOpen);
}
headers.forEach(function (header) {
header.addEventListener(“click”, function () {
toggleAccordion(header);
});
header.addEventListener(“keydown”, function (event) {
if (event.key === “Enter” || event.key === ” “) {
event.preventDefault();
toggleAccordion(header);
}
});
});
})();
(function(){
const sticky =
document.getElementById(“md24lMobileStickyAdopt”);
const purchase =
document.getElementById(“adopt-ducks”);
if(!sticky || !purchase){
return;
}
function updateStickyButton(){
/* Desktop never shows it */
if(window.innerWidth > 760){
sticky.style.display = “none”;
return;
}
const purchaseBottom =
purchase.getBoundingClientRect().bottom;
const pageBottom =
document.documentElement.scrollHeight –
(window.scrollY + window.innerHeight);
/* Hide while purchase section is visible */
if(purchaseBottom > 120){
sticky.style.display = “none”;
return;
}
/* Hide near footer/share section */
if(pageBottom < 450){
sticky.style.display = "none";
return;
}
sticky.style.display = "block";
}
window.addEventListener(
"scroll",
updateStickyButton,
{ passive:true }
);
window.addEventListener(
"resize",
updateStickyButton
);
updateStickyButton();
})();