{"id":55,"date":"2018-04-02T19:53:21","date_gmt":"2018-04-02T19:53:21","guid":{"rendered":"http:\/\/aaparty.co.za\/?page_id=55"},"modified":"2026-03-06T11:19:41","modified_gmt":"2026-03-06T11:19:41","slug":"army-party","status":"publish","type":"page","link":"https:\/\/aaparty.co.za\/index.php\/army-party\/","title":{"rendered":"Army Party"},"content":{"rendered":"<h1>Action packed army party fun!<\/h1>\n<p>Army Party<\/p>\n<p>Duration: 1h30min<\/p>\n<p>Age Appropriate: 6+<\/p>\n<h2>Games include<\/h2>\n<p>Hospital Carry (carry opposite team members from the field back to the hospital)<\/p>\n<p>Baserunning (Simon says type running game)<\/p>\n<p>Leopard crawling<\/p>\n<p>Obstacle course<\/p>\n<p>Tug of war<\/p>\n<p>Grenade wars (dodgeball)<\/p>\n<p>Pushups<\/p>\n<p>Water wars (each player gets a syringe and they defend their base)<\/p>\n<p>Marching<\/p>\n<p>Reaction time relay race<\/p>\n<p>Target shooting with a paintball gun and discipline, discipline, discipline.<\/p>\n<p>Price: R3, 450.00 incl. VAT<\/p>\n<p>Up to 30 Kids<\/p>\n<h2>About the Army Party<\/h2>\n<p>If your child likes the army then a themed army party is probably a great option. During the party, we will get your&nbsp;kids into the spirit of the&nbsp;army by doing drills like marching, pushups, and discipline. Furthermore, this is all done in a fun and exciting way getting the kids active and focusing on the positive attributes of the army. Children attending the party are encouraged to dress up in their army gear because&nbsp;this makes them feel like soldiers. Army facepaint is used to differentiate the teams and focus on the competitive nature of children. We harness that energy to create a fun, exciting and active army party that will keep children entertained for a full 90 minutes. This also&nbsp;helps to purge some of the energy children take on board as a result of standard party treats that all children enjoy.<\/p>\n<p>Shooting a paintball gun at a target is one of the most popular activities that we do in the army party. Since safety is a very important element, the dangers associated with shooting a paintball gun are explained. Control is exercised and children will shoot at a target in turns rather than at each other to ensure the safety of participants in the army party. This is a great activity that all children, from the oldest to the very youngest enjoy and ensure that we end the army party, with a bang!<\/p>\n<p>In conclusion, the Army Party has been one of our most popular parties for many years, it is very adaptable to all ages. As a result, we think it will be a favorite for many years to come.<\/p>\n<h2>Army Party Decor<\/h2>\n<p>Decoration options are wide and varied as a result of choosing the Army Party Theme. Most party shops have big ranges of army and camo themed party decorations. Consequently, if decking out your party to the nines is your thing then the Army Party is a good choice.<\/p>\n<p>Our other party themes:&nbsp;<a href=\"http:\/\/aaparty.co.za\/index.php\/amazing-race-party\/\">Amazing Race<\/a>, <a href=\"http:\/\/aaparty.co.za\/index.php\/army-party\/\">Army<\/a>, <a href=\"http:\/\/aaparty.co.za\/index.php\/camping-party\/\">Camping<\/a>,&nbsp;<a href=\"http:\/\/aaparty.co.za\/index.php\/cricket-party\/\">Cricket<\/a>,&nbsp;<span style=\"font-size: 1rem;\"><a href=\"http:\/\/aaparty.co.za\/index.php\/fear-factor-party\/\">Fear Factor<\/a>,&nbsp;<\/span><span style=\"font-size: 1rem;\"><a href=\"http:\/\/aaparty.co.za\/index.php\/minute-to-win-it-party\/\">Minute to win it<\/a>, <a href=\"http:\/\/aaparty.co.za\/index.php\/nerf-gun-party\/\">Nerf Gun Party<\/a>,&nbsp;<a href=\"http:\/\/aaparty.co.za\/index.php\/ninja-turtle-theme-party\/\">Ninja Turtles<\/a>,&nbsp;<\/span><span style=\"font-size: 1rem;\"><a href=\"http:\/\/aaparty.co.za\/index.php\/pirate-party\/\">Pirate<\/a>,&nbsp;<\/span><span style=\"font-size: 1rem;\"><a href=\"http:\/\/aaparty.co.za\/index.php\/rugby-party\/\">Rugby<\/a>,&nbsp;<\/span><span style=\"font-size: 1rem;\"><a href=\"http:\/\/aaparty.co.za\/index.php\/soccer-party\/\">Soccer<\/a>, <a href=\"http:\/\/aaparty.co.za\/index.php\/space-explorers-party\/\">Space Explorers<\/a>, <a href=\"http:\/\/aaparty.co.za\/index.php\/splash-party\/\">Splash<\/a>, <a href=\"http:\/\/aaparty.co.za\/index.php\/star-wars-party\/\">Star Wars<\/a> and&nbsp;<\/span><span style=\"font-size: 1rem;\"><a href=\"http:\/\/aaparty.co.za\/index.php\/survivor-party\/\">Survivor<\/a>.<\/span><\/p>\n<p>Use our free tool below to generate a PNG invitation to send out on WhatsApp.<\/p>\n\n\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Andy&#8217;s Action Parties \u2013 Army Invitation Generator<\/title>\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Black+Ops+One&#038;family=Oswald:wght@300;400;500;700&#038;family=Special+Elite&#038;display=swap\" rel=\"stylesheet\">\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/html2canvas\/1.4.1\/html2canvas.min.js\"><\/script>\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jspdf\/2.5.1\/jspdf.umd.min.js\"><\/script>\n<style>\n  :root {\n    --od-green: #4a5240;\n    --army-green: #3b4a2f;\n    --camo-dark: #2c3320;\n    --camo-mid: #556b2f;\n    --camo-tan: #8b7355;\n    --camo-brown: #5c4827;\n    --khaki: #c8b87a;\n    --brass: #d4aa50;\n    --cream: #f5f0e0;\n    --red-alert: #cc2200;\n    --stencil-shadow: rgba(0,0,0,0.5);\n  }\n\n  * { box-sizing: border-box; margin: 0; padding: 0; }\n\n  body {\n    background-color: var(--camo-dark);\n    font-family: 'Oswald', sans-serif;\n    overflow-x: hidden;\n  }\n\n  \/* Camo background on wrapper *\/\n\n  .page-wrapper {\n    position: relative;\n    z-index: 1;\n    display: flex;\n    flex-direction: column;\n    max-width: 860px;\n    margin: 0 auto;\n  }\n\n  \/* ========= FORM PANEL ========= *\/\n  .form-panel {\n    background: rgba(20, 26, 14, 0.92);\n    border-right: none;\n    border-bottom: 3px solid var(--brass);\n    padding: 32px 28px;\n    overflow-y: visible;\n    max-height: none;\n    position: static;\n  }\n\n  .brand-header {\n    display: flex;\n    align-items: center;\n    gap: 14px;\n    margin-bottom: 32px;\n    padding-bottom: 20px;\n    border-bottom: 2px dashed var(--camo-mid);\n  }\n\n  .star-badge {\n    width: 52px;\n    height: 52px;\n    background: var(--brass);\n    clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);\n    flex-shrink: 0;\n  }\n\n  .brand-text .company {\n    font-family: 'Black Ops One', cursive;\n    color: var(--brass);\n    font-size: 13px;\n    letter-spacing: 3px;\n    text-transform: uppercase;\n  }\n\n  .brand-text .tagline {\n    font-family: 'Special Elite', cursive;\n    color: var(--khaki);\n    font-size: 11px;\n    letter-spacing: 1px;\n    opacity: 0.7;\n  }\n\n  .panel-title {\n    font-family: 'Black Ops One', cursive;\n    color: var(--cream);\n    font-size: 22px;\n    letter-spacing: 2px;\n    text-transform: uppercase;\n    margin-bottom: 6px;\n  }\n\n  .panel-subtitle {\n    font-family: 'Special Elite', cursive;\n    color: var(--khaki);\n    font-size: 12px;\n    letter-spacing: 1px;\n    margin-bottom: 28px;\n    opacity: 0.8;\n  }\n\n  .field-group {\n    margin-bottom: 18px;\n  }\n\n  label {\n    display: block;\n    font-family: 'Oswald', sans-serif;\n    font-weight: 500;\n    font-size: 11px;\n    letter-spacing: 2.5px;\n    text-transform: uppercase;\n    color: var(--brass);\n    margin-bottom: 6px;\n  }\n\n  input, textarea, select {\n    width: 100%;\n    background: rgba(60, 74, 47, 0.4);\n    border: 1px solid var(--camo-mid);\n    border-bottom: 2px solid var(--brass);\n    color: var(--cream);\n    font-family: 'Special Elite', cursive;\n    font-size: 15px;\n    padding: 10px 14px;\n    outline: none;\n    transition: border-color 0.2s, background 0.2s;\n    border-radius: 0;\n  }\n\n  input:focus, textarea:focus, select:focus {\n    border-color: var(--brass);\n    background: rgba(80, 100, 60, 0.4);\n  }\n\n  input::placeholder, textarea::placeholder {\n    color: rgba(200, 184, 122, 0.3);\n    font-style: italic;\n  }\n\n  select option {\n    background: var(--camo-dark);\n    color: var(--cream);\n  }\n\n  textarea {\n    resize: vertical;\n    min-height: 70px;\n  }\n\n  .field-row {\n    display: grid;\n    grid-template-columns: 1fr 1fr;\n    gap: 14px;\n  }\n\n  .section-divider {\n    display: flex;\n    align-items: center;\n    gap: 10px;\n    margin: 24px 0 18px;\n  }\n\n  .section-divider span {\n    font-family: 'Black Ops One', cursive;\n    font-size: 11px;\n    letter-spacing: 3px;\n    color: var(--camo-tan);\n    white-space: nowrap;\n  }\n\n  .section-divider::before, .section-divider::after {\n    content: '';\n    flex: 1;\n    height: 1px;\n    background: var(--camo-mid);\n  }\n\n  .generate-btn {\n    width: 100%;\n    margin-top: 28px;\n    padding: 16px;\n    background: var(--red-alert);\n    border: none;\n    border-bottom: 4px solid #880000;\n    color: white;\n    font-family: 'Black Ops One', cursive;\n    font-size: 18px;\n    letter-spacing: 3px;\n    text-transform: uppercase;\n    cursor: pointer;\n    position: relative;\n    overflow: hidden;\n    transition: transform 0.1s, border-bottom-width 0.1s;\n  }\n\n  .generate-btn::before {\n    content: '';\n    position: absolute;\n    inset: 0;\n    background: repeating-linear-gradient(\n      45deg,\n      transparent,\n      transparent 8px,\n      rgba(255,255,255,0.05) 8px,\n      rgba(255,255,255,0.05) 16px\n    );\n  }\n\n  .generate-btn:hover { background: #e02600; }\n  .generate-btn:active { transform: translateY(2px); border-bottom-width: 2px; }\n\n  .print-btn {\n    width: 100%;\n    margin-top: 12px;\n    padding: 12px;\n    background: transparent;\n    border: 2px solid var(--brass);\n    color: var(--brass);\n    font-family: 'Oswald', sans-serif;\n    font-weight: 700;\n    font-size: 13px;\n    letter-spacing: 3px;\n    text-transform: uppercase;\n    cursor: pointer;\n    transition: background 0.2s, color 0.2s;\n  }\n\n  .print-btn:hover {\n    background: var(--brass);\n    color: var(--camo-dark);\n  }\n\n  \/* ========= INVITATION PANEL ========= *\/\n  .invitation-panel {\n    display: flex;\n    align-items: flex-start;\n    justify-content: center;\n    padding: 30px 20px 40px;\n    overflow-y: visible;\n    max-height: none;\n    background: rgba(20, 26, 14, 0.5);\n  }\n\n  .invitation-card {\n    width: 100%;\n    max-width: 620px;\n    position: relative;\n    animation: deploy 0.5s ease-out;\n  }\n\n  @keyframes deploy {\n    from { opacity: 0; transform: translateY(20px) scale(0.97); }\n    to { opacity: 1; transform: translateY(0) scale(1); }\n  }\n\n  \/* Outer frame *\/\n  .inv-outer {\n    background: var(--camo-tan);\n    padding: 8px;\n    position: relative;\n    box-shadow:\n      0 0 0 2px var(--camo-brown),\n      0 0 0 4px var(--od-green),\n      0 20px 60px rgba(0,0,0,0.7),\n      inset 0 0 30px rgba(0,0,0,0.3);\n  }\n\n  \/* Camo texture on outer frame *\/\n  .inv-outer::before {\n    content: '';\n    position: absolute;\n    inset: 0;\n    background-image:\n      radial-gradient(ellipse 40px 30px at 15% 20%, var(--camo-brown) 0%, transparent 70%),\n      radial-gradient(ellipse 60px 40px at 70% 10%, var(--od-green) 0%, transparent 70%),\n      radial-gradient(ellipse 30px 50px at 85% 70%, var(--camo-brown) 0%, transparent 70%),\n      radial-gradient(ellipse 50px 35px at 20% 85%, var(--od-green) 0%, transparent 70%);\n    opacity: 0.5;\n  }\n\n  .inv-inner {\n    background: #1a1f12;\n    padding: 34px 30px 30px;\n    position: relative;\n    overflow: hidden;\n  }\n\n  \/* Grid overlay on inner *\/\n  .inv-inner::before {\n    content: '';\n    position: absolute;\n    inset: 0;\n    background-image:\n      linear-gradient(rgba(74, 82, 64, 0.15) 1px, transparent 1px),\n      linear-gradient(90deg, rgba(74, 82, 64, 0.15) 1px, transparent 1px);\n    background-size: 20px 20px;\n    pointer-events: none;\n  }\n\n  \/* Corner brackets *\/\n  .inv-inner::after {\n    content: '';\n    position: absolute;\n    inset: 10px;\n    border: 1px solid rgba(212, 170, 80, 0.3);\n    pointer-events: none;\n  }\n\n  .corner-tl, .corner-tr, .corner-bl, .corner-br {\n    position: absolute;\n    width: 20px;\n    height: 20px;\n    border-color: var(--brass);\n    border-style: solid;\n    z-index: 2;\n  }\n  .corner-tl { top: 10px; left: 10px; border-width: 2px 0 0 2px; }\n  .corner-tr { top: 10px; right: 10px; border-width: 2px 2px 0 0; }\n  .corner-bl { bottom: 10px; left: 10px; border-width: 0 0 2px 2px; }\n  .corner-br { bottom: 10px; right: 10px; border-width: 0 2px 2px 0; }\n\n  \/* Classified stamp *\/\n  .stamp-classified {\n    position: absolute;\n    top: 20px;\n    right: -8px;\n    background: var(--red-alert);\n    color: white;\n    font-family: 'Black Ops One', cursive;\n    font-size: 9px;\n    letter-spacing: 3px;\n    padding: 3px 14px 3px 10px;\n    transform: rotate(3deg);\n    box-shadow: -3px 3px 8px rgba(0,0,0,0.5);\n    z-index: 3;\n  }\n\n  \/* Top badge row *\/\n  .inv-badge-row {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    gap: 12px;\n    margin-bottom: 16px;\n    position: relative;\n    z-index: 1;\n  }\n\n  .rank-star {\n    width: 28px;\n    height: 28px;\n    background: var(--brass);\n    clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);\n    flex-shrink: 0;\n  }\n\n  .inv-ops-code {\n    font-family: 'Oswald', sans-serif;\n    font-weight: 300;\n    font-size: 10px;\n    letter-spacing: 3px;\n    color: var(--camo-mid);\n    text-transform: uppercase;\n  }\n\n  \/* Main headline *\/\n  .inv-headline-block {\n    text-align: center;\n    margin-bottom: 20px;\n    position: relative;\n    z-index: 1;\n  }\n\n  .inv-orders {\n    font-family: 'Oswald', sans-serif;\n    font-weight: 300;\n    font-size: 11px;\n    letter-spacing: 5px;\n    color: var(--brass);\n    text-transform: uppercase;\n    margin-bottom: 4px;\n  }\n\n  .inv-recruit-name {\n    font-family: 'Black Ops One', cursive;\n    color: var(--cream);\n    font-size: 42px;\n    line-height: 1;\n    text-shadow: 3px 3px 0 var(--camo-dark), 0 0 30px rgba(212,170,80,0.2);\n    word-break: break-word;\n    letter-spacing: 2px;\n    text-transform: uppercase;\n    transition: all 0.3s;\n  }\n\n  .inv-mission-tag {\n    font-family: 'Special Elite', cursive;\n    color: var(--khaki);\n    font-size: 13px;\n    margin-top: 6px;\n    letter-spacing: 2px;\n    opacity: 0.85;\n  }\n\n  \/* Age badge *\/\n  .inv-age-badge {\n    display: inline-block;\n    background: var(--red-alert);\n    color: white;\n    font-family: 'Black Ops One', cursive;\n    font-size: 13px;\n    padding: 4px 12px;\n    letter-spacing: 2px;\n    margin-top: 8px;\n    text-transform: uppercase;\n  }\n\n  \/* Divider line *\/\n  .inv-divider {\n    display: flex;\n    align-items: center;\n    gap: 8px;\n    margin: 18px 0;\n    position: relative;\n    z-index: 1;\n  }\n  .inv-divider::before, .inv-divider::after {\n    content: '';\n    flex: 1;\n    height: 1px;\n    background: linear-gradient(to right, transparent, var(--brass), transparent);\n  }\n  .inv-divider-icon {\n    color: var(--brass);\n    font-size: 16px;\n  }\n\n  \/* Mission briefing block *\/\n  .inv-briefing {\n    background: rgba(74, 82, 64, 0.2);\n    border-left: 3px solid var(--brass);\n    padding: 14px 16px;\n    margin-bottom: 18px;\n    position: relative;\n    z-index: 1;\n  }\n\n  .inv-briefing-label {\n    font-family: 'Oswald', sans-serif;\n    font-weight: 700;\n    font-size: 9px;\n    letter-spacing: 3px;\n    color: var(--brass);\n    text-transform: uppercase;\n    margin-bottom: 8px;\n  }\n\n  .inv-briefing-text {\n    font-family: 'Special Elite', cursive;\n    color: var(--cream);\n    font-size: 14px;\n    line-height: 1.6;\n    opacity: 0.9;\n  }\n\n  \/* Intel grid *\/\n  .inv-intel-grid {\n    display: grid;\n    grid-template-columns: 1fr 1fr;\n    gap: 12px;\n    margin-bottom: 18px;\n    position: relative;\n    z-index: 1;\n  }\n\n  .inv-intel-item {\n    background: rgba(44, 51, 32, 0.5);\n    border: 1px solid rgba(212, 170, 80, 0.25);\n    padding: 10px 12px;\n  }\n\n  .inv-intel-label {\n    font-family: 'Oswald', sans-serif;\n    font-weight: 500;\n    font-size: 9px;\n    letter-spacing: 3px;\n    color: var(--brass);\n    text-transform: uppercase;\n    margin-bottom: 4px;\n  }\n\n  .inv-intel-value {\n    font-family: 'Special Elite', cursive;\n    color: var(--cream);\n    font-size: 13px;\n    line-height: 1.4;\n    word-break: break-word;\n  }\n\n  .inv-intel-full {\n    grid-column: 1 \/ -1;\n  }\n\n  \/* RSVP block *\/\n  .inv-rsvp {\n    background: rgba(204, 34, 0, 0.12);\n    border: 1px dashed var(--red-alert);\n    padding: 14px 16px;\n    text-align: center;\n    position: relative;\n    z-index: 1;\n    margin-bottom: 16px;\n  }\n\n  .inv-rsvp-label {\n    font-family: 'Black Ops One', cursive;\n    color: var(--red-alert);\n    font-size: 11px;\n    letter-spacing: 4px;\n    margin-bottom: 4px;\n    text-transform: uppercase;\n  }\n\n  .inv-rsvp-value {\n    font-family: 'Special Elite', cursive;\n    color: var(--cream);\n    font-size: 14px;\n  }\n\n  \/* Footer *\/\n  .inv-footer {\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    position: relative;\n    z-index: 1;\n    padding-top: 12px;\n    border-top: 1px dashed rgba(74, 82, 64, 0.6);\n  }\n\n  .inv-footer-brand {\n    font-family: 'Black Ops One', cursive;\n    color: var(--camo-mid);\n    font-size: 9px;\n    letter-spacing: 2px;\n    text-transform: uppercase;\n  }\n\n  .inv-footer-stars {\n    display: flex;\n    gap: 4px;\n  }\n\n  .inv-footer-star {\n    width: 10px;\n    height: 10px;\n    background: var(--camo-mid);\n    clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);\n  }\n\n  \/* Dog tag watermark *\/\n  .inv-dogtag-watermark {\n    position: absolute;\n    bottom: 40px;\n    right: 20px;\n    font-family: 'Black Ops One', cursive;\n    font-size: 80px;\n    color: rgba(74, 82, 64, 0.06);\n    pointer-events: none;\n    line-height: 1;\n    z-index: 0;\n    transform: rotate(-15deg);\n  }\n\n  \/* Placeholder state *\/\n  .placeholder-name {\n    color: rgba(200, 184, 122, 0.25) !important;\n    font-size: 32px !important;\n  }\n\n  \/* ========= RESPONSIVE ========= *\/\n  \/* On wider screens, put form fields in two columns to keep form compact *\/\n  @media (min-width: 600px) {\n    .form-two-col {\n      display: grid;\n      grid-template-columns: 1fr 1fr;\n      gap: 14px;\n    }\n    .form-two-col .field-group {\n      margin-bottom: 0;\n    }\n  }\n\n  @media print {\n    body { background: white; }\n    body::before { display: none; }\n    .form-panel { display: none; }\n    .invitation-panel { padding: 0; justify-content: center; }\n    .inv-outer { box-shadow: none; }\n  }\n<\/style>\n<\/head>\n<body>\n\n<div class=\"page-wrapper\">\n\n  <!-- FORM PANEL -->\n  <div class=\"form-panel\">\n    <div class=\"brand-header\">\n      <div class=\"star-badge\"><\/div>\n      <div class=\"brand-text\">\n        <div class=\"company\">Andy&#8217;s Action Parties<\/div>\n        <div class=\"tagline\">Elite Party Operations Since Day One<\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"panel-title\">Mission Briefing<\/div>\n    <div class=\"panel-subtitle\">\/\/ FILL IN DETAILS \u2014 INVITATION GENERATES INSTANTLY \/\/<\/div>\n\n    <div class=\"field-group\">\n      <label>Recruit&#8217;s Name (Birthday Star)<\/label>\n      <input type=\"text\" id=\"recruitName\" placeholder=\"e.g. Charlie\" oninput=\"updateInvitation()\" \/>\n    <\/div>\n\n    <div class=\"field-row\">\n      <div class=\"field-group\">\n        <label>Turning Age<\/label>\n        <input type=\"number\" id=\"age\" placeholder=\"e.g. 7\" min=\"1\" max=\"99\" oninput=\"updateInvitation()\" \/>\n      <\/div>\n      <div class=\"field-group\">\n        <label>Rank \/ Theme Tag<\/label>\n        <select id=\"rank\" onchange=\"updateInvitation()\">\n          <option value=\"GENERAL\">General<\/option>\n          <option value=\"COLONEL\">Colonel<\/option>\n          <option value=\"MAJOR\">Major<\/option>\n          <option value=\"CAPTAIN\" selected>Captain<\/option>\n          <option value=\"SERGEANT\">Sergeant<\/option>\n          <option value=\"CORPORAL\">Corporal<\/option>\n          <option value=\"PRIVATE\">Private<\/option>\n        <\/select>\n      <\/div>\n    <\/div>\n\n    <div class=\"section-divider\"><span>\/\/ MISSION DATE &amp; TIME \/\/<\/span><\/div>\n\n    <div class=\"field-row\">\n      <div class=\"field-group\">\n        <label>Date of Operation<\/label>\n        <input type=\"date\" id=\"date\" oninput=\"updateInvitation()\" \/>\n      <\/div>\n      <div class=\"field-group\">\n        <label>Deployment Time<\/label>\n        <input type=\"time\" id=\"time\" oninput=\"updateInvitation()\" \/>\n      <\/div>\n    <\/div>\n\n    <div class=\"section-divider\"><span>\/\/ BASE LOCATION \/\/<\/span><\/div>\n\n    <div class=\"field-group\">\n      <label>Base of Operations (Venue Name)<\/label>\n      <input type=\"text\" id=\"venue\" placeholder=\"e.g. The Johnson Backyard HQ\" oninput=\"updateInvitation()\" \/>\n    <\/div>\n\n    <div class=\"field-group\">\n      <label>Coordinates (Address)<\/label>\n      <input type=\"text\" id=\"address\" placeholder=\"e.g. 42 Oak Street, Springfield\" oninput=\"updateInvitation()\" \/>\n    <\/div>\n\n    <div class=\"section-divider\"><span>\/\/ BRIEFING MESSAGE \/\/<\/span><\/div>\n\n    <div class=\"field-group\">\n      <label>Mission Briefing (Personal Message)<\/label>\n      <textarea id=\"message\" placeholder=\"e.g. All soldiers report for duty! Come dressed in camo, ready for games, food and fun!\" oninput=\"updateInvitation()\"><\/textarea>\n    <\/div>\n\n    <div class=\"section-divider\"><span>\/\/ RSVP INTEL \/\/<\/span><\/div>\n\n    <div class=\"field-row\">\n      <div class=\"field-group\">\n        <label>RSVP Contact Name<\/label>\n        <input type=\"text\" id=\"rsvpName\" placeholder=\"e.g. Mrs. Johnson\" oninput=\"updateInvitation()\" \/>\n      <\/div>\n      <div class=\"field-group\">\n        <label>RSVP Deadline<\/label>\n        <input type=\"date\" id=\"rsvpDate\" oninput=\"updateInvitation()\" \/>\n      <\/div>\n    <\/div>\n\n    <div class=\"field-group\">\n      <label>RSVP Phone \/ Email<\/label>\n      <input type=\"text\" id=\"rsvpContact\" placeholder=\"e.g. 071 234 5678 or mom@email.com\" oninput=\"updateInvitation()\" \/>\n    <\/div>\n\n    <button class=\"generate-btn\" onclick=\"generateInvitation()\">\u26a1 Deploy Invitation<\/button>\n    <button class=\"print-btn\" id=\"printBtn\" onclick=\"saveAsPDF()\">\ud83d\udda8 Save Invitation as PNG<\/button>\n  <\/div>\n\n  <!-- INVITATION PREVIEW PANEL -->\n  <div class=\"invitation-panel\">\n    <div class=\"invitation-card\" id=\"invitationCard\">\n      <div class=\"inv-outer\">\n        <div class=\"inv-inner\">\n          <div class=\"corner-tl\"><\/div>\n          <div class=\"corner-tr\"><\/div>\n          <div class=\"corner-bl\"><\/div>\n          <div class=\"corner-br\"><\/div>\n          <div class=\"stamp-classified\">CLASSIFIED<\/div>\n          <div class=\"inv-dogtag-watermark\">\u2605<\/div>\n\n          <div class=\"inv-badge-row\">\n            <div class=\"rank-star\"><\/div>\n            <span class=\"inv-ops-code\">OPERATION BIRTHDAY \u2014 ANDY&#8217;S ACTION PARTIES<\/span>\n            <div class=\"rank-star\"><\/div>\n          <\/div>\n\n          <div class=\"inv-headline-block\">\n            <div class=\"inv-orders\">YOU HAVE BEEN CALLED TO SERVE<\/div>\n            <div class=\"inv-recruit-name placeholder-name\" id=\"inv-name\">SOLDIER&#8217;S NAME<\/div>\n            <div class=\"inv-mission-tag\" id=\"inv-mission-tag\">IS TURNING AN AGE<\/div>\n            <div id=\"inv-age-badge-wrap\"><\/div>\n          <\/div>\n\n          <div class=\"inv-divider\"><span class=\"inv-divider-icon\">\u2726<\/span><\/div>\n\n          <div class=\"inv-briefing\" id=\"inv-briefing-wrap\">\n            <div class=\"inv-briefing-label\">\u25b6 Mission Briefing<\/div>\n            <div class=\"inv-briefing-text\" id=\"inv-briefing-text\">\n              All operatives are ordered to report for birthday party duty. Be prepared for fun, food and adventure!\n            <\/div>\n          <\/div>\n\n          <div class=\"inv-intel-grid\">\n            <div class=\"inv-intel-item\">\n              <div class=\"inv-intel-label\">\ud83d\udcc5 Date<\/div>\n              <div class=\"inv-intel-value\" id=\"inv-date\">\u2014<\/div>\n            <\/div>\n            <div class=\"inv-intel-item\">\n              <div class=\"inv-intel-label\">\ud83d\udd50 Time<\/div>\n              <div class=\"inv-intel-value\" id=\"inv-time\">\u2014<\/div>\n            <\/div>\n            <div class=\"inv-intel-item inv-intel-full\">\n              <div class=\"inv-intel-label\">\ud83d\udccd Base of Operations<\/div>\n              <div class=\"inv-intel-value\" id=\"inv-venue\">\u2014<\/div>\n            <\/div>\n            <div class=\"inv-intel-item inv-intel-full\">\n              <div class=\"inv-intel-label\">\ud83d\uddfa Coordinates<\/div>\n              <div class=\"inv-intel-value\" id=\"inv-address\">\u2014<\/div>\n            <\/div>\n          <\/div>\n\n          <div class=\"inv-rsvp\">\n            <div class=\"inv-rsvp-label\">\ud83c\udf96 RSVP \u2014 Confirm Your Orders<\/div>\n            <div class=\"inv-rsvp-value\" id=\"inv-rsvp\">Fill in RSVP details above<\/div>\n          <\/div>\n\n          <div class=\"inv-footer\">\n            <div class=\"inv-footer-brand\">Andy&#8217;s Action Parties<\/div>\n            <div class=\"inv-footer-stars\">\n              <div class=\"inv-footer-star\"><\/div>\n              <div class=\"inv-footer-star\"><\/div>\n              <div class=\"inv-footer-star\"><\/div>\n              <div class=\"inv-footer-star\"><\/div>\n              <div class=\"inv-footer-star\"><\/div>\n            <\/div>\n          <\/div>\n        <\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\n  function formatDate(dateStr) {\n    if (!dateStr) return '\u2014';\n    const d = new Date(dateStr + 'T00:00:00');\n    return d.toLocaleDateString('en-ZA', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });\n  }\n\n  function formatTime(timeStr) {\n    if (!timeStr) return '\u2014';\n    const [h, m] = timeStr.split(':');\n    const hour = parseInt(h);\n    const ampm = hour >= 12 ? 'PM' : 'AM';\n    const h12 = hour % 12 || 12;\n    return `${h12}:${m} ${ampm}`;\n  }\n\n  function updateInvitation() {\n    const name = document.getElementById('recruitName').value.trim();\n    const age = document.getElementById('age').value.trim();\n    const rank = document.getElementById('rank').value;\n    const date = document.getElementById('date').value;\n    const time = document.getElementById('time').value;\n    const venue = document.getElementById('venue').value.trim();\n    const address = document.getElementById('address').value.trim();\n    const message = document.getElementById('message').value.trim();\n    const rsvpName = document.getElementById('rsvpName').value.trim();\n    const rsvpDate = document.getElementById('rsvpDate').value;\n    const rsvpContact = document.getElementById('rsvpContact').value.trim();\n\n    \/\/ Name\n    const nameEl = document.getElementById('inv-name');\n    if (name) {\n      nameEl.textContent = name.toUpperCase();\n      nameEl.classList.remove('placeholder-name');\n    } else {\n      nameEl.textContent = \"SOLDIER'S NAME\";\n      nameEl.classList.add('placeholder-name');\n    }\n\n    \/\/ Mission tag\n    const missionTag = document.getElementById('inv-mission-tag');\n    if (name && age) {\n      missionTag.textContent = `${rank} ${name} is turning ${age}!`;\n    } else if (name) {\n      missionTag.textContent = `${rank} ${name}'s Birthday Mission`;\n    } else {\n      missionTag.textContent = 'IS TURNING AN AGE';\n    }\n\n    \/\/ Age badge\n    const ageBadgeWrap = document.getElementById('inv-age-badge-wrap');\n    if (age) {\n      ageBadgeWrap.innerHTML = `<div class=\"inv-age-badge\">MISSION: TURNING ${age}<\/div>`;\n    } else {\n      ageBadgeWrap.innerHTML = '';\n    }\n\n    \/\/ Message\n    const briefingText = document.getElementById('inv-briefing-text');\n    briefingText.textContent = message || 'All operatives are ordered to report for birthday party duty. Be prepared for fun, food and adventure!';\n\n    \/\/ Date & time\n    document.getElementById('inv-date').textContent = date ? formatDate(date) : '\u2014';\n    document.getElementById('inv-time').textContent = time ? formatTime(time) : '\u2014';\n\n    \/\/ Venue\n    document.getElementById('inv-venue').textContent = venue || '\u2014';\n    document.getElementById('inv-address').textContent = address || '\u2014';\n\n    \/\/ RSVP\n    const rsvpEl = document.getElementById('inv-rsvp');\n    let rsvpParts = [];\n    if (rsvpName) rsvpParts.push(`Contact: ${rsvpName}`);\n    if (rsvpContact) rsvpParts.push(rsvpContact);\n    if (rsvpDate) rsvpParts.push(`By: ${formatDate(rsvpDate)}`);\n    rsvpEl.textContent = rsvpParts.length ? rsvpParts.join(' \u2022 ') : 'Fill in RSVP details above';\n  }\n\n  function generateInvitation() {\n    updateInvitation();\n    const card = document.getElementById('invitationCard');\n    card.style.animation = 'none';\n    card.offsetHeight;\n    card.style.animation = 'deploy 0.5s ease-out';\n  }\n\n  async function saveAsPDF() {\n    const btn = document.getElementById('printBtn');\n    btn.textContent = '\u23f3 Drawing...';\n    btn.disabled = true;\n\n    const recruitName = document.getElementById('recruitName').value.trim() || 'SOLDIER';\n    const age         = document.getElementById('age').value.trim();\n    const rank        = document.getElementById('rank').value;\n    const date        = document.getElementById('date').value;\n    const time        = document.getElementById('time').value;\n    const venue       = document.getElementById('venue').value.trim() || '\u2014';\n    const address     = document.getElementById('address').value.trim() || '\u2014';\n    const message     = document.getElementById('message').value.trim() || 'All operatives are ordered to report for birthday party duty. Be prepared for fun, food and adventure!';\n    const rsvpName    = document.getElementById('rsvpName').value.trim();\n    const rsvpDate    = document.getElementById('rsvpDate').value;\n    const rsvpContact = document.getElementById('rsvpContact').value.trim();\n\n    let rsvpParts = [];\n    if(rsvpName)    rsvpParts.push('Contact: ' + rsvpName);\n    if(rsvpContact) rsvpParts.push(rsvpContact);\n    if(rsvpDate)    rsvpParts.push('By: ' + formatDate(rsvpDate));\n    const rsvpStr = rsvpParts.length ? rsvpParts.join('  \u2022  ') : 'RSVP details not provided';\n\n    \/\/ \u2500\u2500 Layout constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    const W       = 900;\n    const MARGIN  = 40;\n    const PAD     = 30;\n    const BX      = MARGIN + PAD;           \/\/ block left x\n    const BW      = W - (MARGIN + PAD) * 2; \/\/ block width\n    const COL_GAP = 10;\n    const COL_W   = (BW - COL_GAP) \/ 2;\n\n    const MSG_FONT  = '18px Georgia,serif';\n    const VAL_FONT  = '17px Georgia,serif';\n    const RSVP_FONT = '17px Georgia,serif';\n    const CELL_LINE = 24;\n    const MSG_LINE  = 28;\n\n    \/\/ \u2500\u2500 Pre-measure text to compute dynamic canvas height \u2500\u2500\u2500\u2500\u2500\n    const tmp = document.createElement('canvas').getContext('2d');\n\n    function countWrapLines(text, font, maxW) {\n      tmp.font = font;\n      const words = String(text).split(' ');\n      let line = '', n = 0;\n      for (const w of words) {\n        const t = line ? line + ' ' + w : w;\n        if (tmp.measureText(t).width > maxW && line) { n++; line = w; }\n        else line = t;\n      }\n      if (line) n++;\n      return n;\n    }\n\n    const msgLines   = countWrapLines(message, MSG_FONT, BW - 36);\n    const venueLines = countWrapLines(venue,   VAL_FONT, BW - 28);\n    const addrLines  = countWrapLines(address, VAL_FONT, BW - 28);\n    const rsvpLines  = countWrapLines(rsvpStr, RSVP_FONT, BW - 48);\n\n    const CELL_MIN   = 58;\n    const venueH     = Math.max(CELL_MIN, venueLines * CELL_LINE + 36);\n    const addrH      = Math.max(CELL_MIN, addrLines  * CELL_LINE + 36);\n    const dateTimeH  = 58;\n    const briefingH  = msgLines * MSG_LINE + 44;\n    const rsvpH      = rsvpLines * CELL_LINE + 58;\n\n    const nameFontEst = recruitName.length <= 8 ? 72 : recruitName.length <= 12 ? 58 : 44;\n\n    const H =\n      MARGIN + 50 +           \/\/ top pad + badge row\n      46 +                    \/\/ \"called to serve\" label\n      nameFontEst + 22 +      \/\/ big name (dynamic)\n      36 +                    \/\/ mission tag\n      (age ? 50 : 0) +       \/\/ age badge\n      32 +                    \/\/ divider\n      briefingH + 12 +        \/\/ briefing block\n      dateTimeH + COL_GAP +   \/\/ date\/time row\n      venueH + COL_GAP +      \/\/ venue cell\n      addrH + 16 +            \/\/ address cell\n      rsvpH + 20 +            \/\/ rsvp block\n      50 +                    \/\/ footer\n      MARGIN + 20;            \/\/ bottom pad\n\n    \/\/ \u2500\u2500 Create canvas \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    const canvas = document.createElement('canvas');\n    canvas.width = W; canvas.height = H;\n    const c = canvas.getContext('2d');\n\n    \/\/ \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    function roundRect(x,y,w,h,r=2){\n      c.beginPath();\n      c.moveTo(x+r,y); c.lineTo(x+w-r,y); c.arcTo(x+w,y,x+w,y+r,r);\n      c.lineTo(x+w,y+h-r); c.arcTo(x+w,y+h,x+w-r,y+h,r);\n      c.lineTo(x+r,y+h); c.arcTo(x,y+h,x,y+h-r,r);\n      c.lineTo(x,y+r); c.arcTo(x,y,x+r,y,r);\n      c.closePath();\n    }\n\n    function wrapDraw(text, x, y, maxW, lineH, align) {\n      c.textAlign = align || 'left';\n      const words = String(text).split(' ');\n      let line = '', lines = [];\n      for (const w of words) {\n        const t = line ? line + ' ' + w : w;\n        if (c.measureText(t).width > maxW && line) { lines.push(line); line = w; }\n        else line = t;\n      }\n      if (line) lines.push(line);\n      lines.forEach((l, i) => c.fillText(l, x, y + i * lineH));\n      return lines.length;\n    }\n\n    function drawStar(cx, cy, r, color) {\n      c.save(); c.fillStyle = color; c.beginPath();\n      for (let i = 0; i < 5; i++) {\n        const oa = (Math.PI*2\/5)*i - Math.PI\/2;\n        const ia = oa + Math.PI\/5;\n        if (i === 0) c.moveTo(cx + r*Math.cos(oa), cy + r*Math.sin(oa));\n        else         c.lineTo(cx + r*Math.cos(oa), cy + r*Math.sin(oa));\n        c.lineTo(cx + r*0.4*Math.cos(ia), cy + r*0.4*Math.sin(ia));\n      }\n      c.closePath(); c.fill(); c.restore();\n    }\n\n    function intelCell(x, y, w, h, label, value) {\n      c.fillStyle = 'rgba(44,51,32,0.65)';\n      roundRect(x, y, w, h); c.fill();\n      c.save(); c.strokeStyle = 'rgba(212,170,80,0.25)'; c.lineWidth = 1;\n      roundRect(x, y, w, h); c.stroke(); c.restore();\n      c.fillStyle = '#d4aa50'; c.font = 'bold 10px Arial'; c.textAlign = 'left';\n      c.fillText(label, x+14, y+17);\n      c.fillStyle = '#f5f0e0'; c.font = VAL_FONT;\n      wrapDraw(value, x+14, y+36, w-28, CELL_LINE, 'left');\n    }\n\n    \/\/ \u2500\u2500 BACKGROUND \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    c.fillStyle = '#1a2010'; c.fillRect(0, 0, W, H);\n\n    \/\/ Camo blobs\n    const blobs = [\n      [0.08,0.10,160,110,'#3b4a2f'],[0.75,0.08,130,100,'#4a5240'],\n      [0.30,0.50,200,130,'#4a5240'],[0.85,0.40,150,100,'#3b4a2f'],\n      [0.12,0.82,140,90, '#3d3018'],[0.90,0.80,140,160,'#4a5240'],\n      [0.50,0.30,110,80, '#3d3018'],[0.55,0.88,170,110,'#3b4a2f'],\n    ];\n    blobs.forEach(([bx2,by2,rx,ry,col]) => {\n      const g = c.createRadialGradient(bx2*W, by2*H, 0, bx2*W, by2*H, Math.max(rx,ry));\n      g.addColorStop(0, col + 'bb'); g.addColorStop(1, 'transparent');\n      c.save(); c.scale(1, ry\/rx);\n      c.fillStyle = g; c.beginPath();\n      c.arc(bx2*W, by2*H*(rx\/ry), rx, 0, Math.PI*2);\n      c.fill(); c.restore();\n    });\n\n    \/\/ Grid\n    c.save(); c.strokeStyle = 'rgba(74,82,64,0.15)'; c.lineWidth = 1;\n    for (let x=0; x<W; x+=26) { c.beginPath(); c.moveTo(x,0); c.lineTo(x,H); c.stroke(); }\n    for (let y=0; y<H; y+=26) { c.beginPath(); c.moveTo(0,y); c.lineTo(W,y); c.stroke(); }\n    c.restore();\n\n    \/\/ \u2500\u2500 OUTER CAMO FRAME \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    const FP = 22;\n    c.fillStyle = '#7a6448';\n    roundRect(FP, FP, W-FP*2, H-FP*2, 4); c.fill();\n\n    \/\/ camo blobs on frame\n    [[0.05,0.06,'#4a3820'],[0.88,0.04,'#3b4a2f'],[0.94,0.94,'#4a3820'],[0.06,0.94,'#3b4a2f']].forEach(([fx,fy,fc]) => {\n      const fg = c.createRadialGradient(fx*W, fy*H, 0, fx*W, fy*H, 90);\n      fg.addColorStop(0, fc+'99'); fg.addColorStop(1, 'transparent');\n      c.fillStyle = fg; c.fillRect(0, 0, W, H);\n    });\n\n    \/\/ \u2500\u2500 INNER DARK CARD \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    const IP = MARGIN;\n    c.fillStyle = '#121810';\n    roundRect(IP, IP, W-IP*2, H-IP*2, 2); c.fill();\n\n    \/\/ Grid on inner\n    c.save(); c.strokeStyle = 'rgba(74,82,64,0.10)'; c.lineWidth = 1;\n    for (let x=IP; x<W-IP; x+=22) { c.beginPath(); c.moveTo(x,IP); c.lineTo(x,H-IP); c.stroke(); }\n    for (let y=IP; y<H-IP; y+=22) { c.beginPath(); c.moveTo(IP,y); c.lineTo(W-IP,y); c.stroke(); }\n    c.restore();\n\n    \/\/ Gold inner border\n    c.save(); c.strokeStyle = 'rgba(212,170,80,0.3)'; c.lineWidth = 1.5;\n    roundRect(IP+12, IP+12, W-IP*2-24, H-IP*2-24, 2); c.stroke(); c.restore();\n\n    \/\/ Corner brackets\n    const CBX = IP+12, CBY = IP+12, CBW = W-IP*2-24, CBH = H-IP*2-24, CBS = 30;\n    c.save(); c.strokeStyle = '#d4aa50'; c.lineWidth = 3;\n    [[CBX,CBY,1,1],[CBX+CBW,CBY,-1,1],[CBX,CBY+CBH,1,-1],[CBX+CBW,CBY+CBH,-1,-1]].forEach(([px,py,dx,dy]) => {\n      c.beginPath(); c.moveTo(px+dx*CBS, py); c.lineTo(px,py); c.lineTo(px, py+dy*CBS); c.stroke();\n    });\n    c.restore();\n\n    \/\/ \u2500\u2500 CLASSIFIED STAMP \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    c.save();\n    c.translate(W - IP - 8, IP + 28);\n    c.rotate(0.05);\n    c.fillStyle = '#cc2200'; c.fillRect(-96, -20, 96, 24);\n    c.fillStyle = 'white'; c.font = 'bold 12px Arial'; c.textAlign = 'center';\n    c.fillText('CLASSIFIED', -48, 0);\n    c.restore();\n\n    \/\/ \u2500\u2500 WATERMARK \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    c.save(); c.globalAlpha = 0.035; c.fillStyle = '#c8b87a';\n    c.font = 'bold 300px Arial'; c.textAlign = 'center'; c.textBaseline = 'middle';\n    c.fillText('\u2605', W*0.68, H*0.55); c.restore();\n\n    \/\/ \u2500\u2500 NOW DRAW CONTENT (cursor = cy) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    let cy = IP + 52;\n    c.textAlign = 'center';\n\n    \/\/ Badge row\n    drawStar(BX + 20, cy + 4, 16, '#d4aa50');\n    drawStar(BX + BW - 20, cy + 4, 16, '#d4aa50');\n    c.fillStyle = 'rgba(85,107,47,0.75)'; c.font = '500 12px Arial';\n    c.fillText(\"OPERATION BIRTHDAY \u2014 ANDY'S ACTION PARTIES\", W\/2, cy + 8);\n    cy += 46;\n\n    \/\/ Called to serve\n    c.fillStyle = 'rgba(212,170,80,0.65)'; c.font = '300 13px Arial';\n    c.fillText('YOU HAVE BEEN CALLED TO SERVE', W\/2, cy);\n    cy += 12;\n\n    \/\/ Big name \u2014 scale font size based on name length\n    const nameFontSize = recruitName.length <= 8 ? 72 : recruitName.length <= 12 ? 58 : 44;\n    c.save();\n    c.font = `bold ${nameFontSize}px \"Black Ops One\", \"Arial Black\", Arial`;\n    c.fillStyle = 'rgba(0,0,0,0.45)'; c.fillText(recruitName.toUpperCase(), W\/2+3, cy+nameFontSize+6);\n    c.fillStyle = '#f5f0e0';\n    c.shadowColor = 'rgba(212,170,80,0.25)'; c.shadowBlur = 24;\n    c.fillText(recruitName.toUpperCase(), W\/2, cy+nameFontSize+2);\n    c.restore();\n    cy += nameFontSize + 20;\n\n    \/\/ Mission tag\n    c.fillStyle = '#c8b87a'; c.font = 'italic 18px Georgia, serif';\n    const missionStr = age ? rank+' '+recruitName+' is turning '+age+'!' : rank+' '+recruitName+\"'s Birthday Mission\";\n    c.fillText(missionStr, W\/2, cy);\n    cy += 8;\n\n    \/\/ Age badge\n    if (age) {\n      cy += 10;\n      const badgeTxt = 'MISSION: TURNING ' + age;\n      c.font = 'bold 15px Arial';\n      const bw2 = c.measureText(badgeTxt).width + 44;\n      c.fillStyle = '#cc2200'; c.fillRect(W\/2 - bw2\/2, cy, bw2, 30);\n      c.fillStyle = 'white'; c.fillText(badgeTxt, W\/2, cy + 21);\n      cy += 44;\n    } else {\n      cy += 20;\n    }\n\n    \/\/ Divider\n    cy += 8;\n    const dg = c.createLinearGradient(BX, 0, BX+BW, 0);\n    dg.addColorStop(0,'transparent'); dg.addColorStop(0.5,'#d4aa50'); dg.addColorStop(1,'transparent');\n    c.strokeStyle = dg; c.lineWidth = 1.5;\n    c.beginPath(); c.moveTo(BX, cy); c.lineTo(BX+BW, cy); c.stroke();\n    c.fillStyle = '#d4aa50'; c.font = '16px serif'; c.fillText('\u2726', W\/2, cy+7);\n    cy += 22;\n\n    \/\/ \u2500\u2500 MISSION BRIEFING \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    const brTop = cy;\n    c.fillStyle = 'rgba(64,78,50,0.22)';\n    c.fillRect(BX, brTop, BW, briefingH);\n\n    c.save(); c.fillStyle = '#d4aa50'; c.fillRect(BX, brTop, 4, briefingH); c.restore();\n\n    c.fillStyle = '#d4aa50'; c.font = 'bold 11px Arial'; c.textAlign = 'left';\n    c.fillText('\u25b6  MISSION BRIEFING', BX+16, cy+18);\n    cy += 36;\n    c.fillStyle = '#f5f0e0'; c.font = MSG_FONT;\n    wrapDraw(message, BX+16, cy, BW-32, MSG_LINE, 'left');\n    cy = brTop + briefingH + 12;\n\n    \/\/ \u2500\u2500 DATE \/ TIME ROW \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    intelCell(BX,            cy, COL_W,      dateTimeH, '\ud83d\udcc5  DATE', date ? formatDate(date) : '\u2014');\n    intelCell(BX+COL_W+COL_GAP, cy, COL_W,  dateTimeH, '\ud83d\udd50  TIME', time ? formatTime(time) : '\u2014');\n    cy += dateTimeH + COL_GAP;\n\n    \/\/ \u2500\u2500 VENUE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    intelCell(BX, cy, BW, venueH, '\ud83d\udccd  BASE OF OPERATIONS', venue);\n    cy += venueH + COL_GAP;\n\n    \/\/ \u2500\u2500 ADDRESS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    intelCell(BX, cy, BW, addrH, '\ud83d\uddfa  COORDINATES', address);\n    cy += addrH + 16;\n\n    \/\/ \u2500\u2500 RSVP \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    c.save(); c.strokeStyle = '#cc2200'; c.lineWidth = 2; c.setLineDash([8,5]);\n    c.strokeRect(BX, cy, BW, rsvpH); c.setLineDash([]); c.restore();\n    c.fillStyle = 'rgba(204,34,0,0.08)'; c.fillRect(BX, cy, BW, rsvpH);\n\n    c.fillStyle = '#cc2200'; c.font = 'bold 12px Arial'; c.textAlign = 'center';\n    c.fillText('\ud83c\udf96  RSVP \u2014 CONFIRM YOUR ORDERS', W\/2, cy + 22);\n\n    \/\/ thin separator\n    c.save(); c.strokeStyle = 'rgba(204,34,0,0.4)'; c.lineWidth = 1;\n    c.beginPath(); c.moveTo(BX+16, cy+32); c.lineTo(BX+BW-16, cy+32); c.stroke(); c.restore();\n\n    c.fillStyle = '#f5f0e0'; c.font = RSVP_FONT; c.textAlign = 'center';\n    wrapDraw(rsvpStr, W\/2, cy + 50, BW - 48, CELL_LINE, 'center');\n    cy += rsvpH + 20;\n\n    \/\/ \u2500\u2500 FOOTER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    c.save(); c.strokeStyle = 'rgba(74,82,64,0.45)'; c.lineWidth = 1; c.setLineDash([6,5]);\n    c.beginPath(); c.moveTo(BX, cy); c.lineTo(BX+BW, cy); c.stroke();\n    c.setLineDash([]); c.restore();\n    cy += 18;\n    c.fillStyle = 'rgba(85,107,47,0.65)'; c.font = 'bold 11px Arial'; c.textAlign = 'left';\n    c.fillText(\"ANDY'S ACTION PARTIES\", BX, cy + 10);\n    for (let i = 0; i < 5; i++) drawStar(BX+BW-10 - i*22, cy+6, 8, 'rgba(85,107,47,0.65)');\n\n    \/\/ \u2500\u2500 DOWNLOAD \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    const link = document.createElement('a');\n    link.download = 'andys-action-party-' + recruitName.toLowerCase().replace(\/\\s+\/g,'-') + '.png';\n    link.href = canvas.toDataURL('image\/png');\n    link.click();\n\n    btn.textContent = '\ud83d\udda8 Save Invitation as PNG';\n    btn.disabled = false;\n  }\n\n  updateInvitation();\n<\/script>\n<\/body>\n<\/html>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Action packed army party fun! Army Party Duration: 1h30min Age Appropriate: 6+ Games include Hospital Carry (carry opposite team members from the field back to the hospital) Baserunning (Simon says type running game) Leopard crawling Obstacle course Tug of war Grenade wars (dodgeball) Pushups Water wars (each player gets a syringe and they defend their &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/aaparty.co.za\/index.php\/army-party\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Army Party&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":57,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"open","template":"","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"ngg_post_thumbnail":0,"footnotes":""},"class_list":["post-55","page","type-page","status-publish","has-post-thumbnail","hentry"],"_links":{"self":[{"href":"https:\/\/aaparty.co.za\/index.php\/wp-json\/wp\/v2\/pages\/55","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/aaparty.co.za\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/aaparty.co.za\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/aaparty.co.za\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/aaparty.co.za\/index.php\/wp-json\/wp\/v2\/comments?post=55"}],"version-history":[{"count":38,"href":"https:\/\/aaparty.co.za\/index.php\/wp-json\/wp\/v2\/pages\/55\/revisions"}],"predecessor-version":[{"id":16210,"href":"https:\/\/aaparty.co.za\/index.php\/wp-json\/wp\/v2\/pages\/55\/revisions\/16210"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/aaparty.co.za\/index.php\/wp-json\/wp\/v2\/media\/57"}],"wp:attachment":[{"href":"https:\/\/aaparty.co.za\/index.php\/wp-json\/wp\/v2\/media?parent=55"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}