{"id":132866,"date":"2025-04-30T23:19:23","date_gmt":"2025-05-01T02:19:23","guid":{"rendered":"https:\/\/www.lawnstarter.com\/blog\/?page_id=132866"},"modified":"2026-05-06T10:13:21","modified_gmt":"2026-05-06T13:13:21","slug":"lawnstarter-industry-report","status":"publish","type":"page","link":"https:\/\/www.lawnstarter.com\/blog\/statistics\/lawnstarter-industry-report\/","title":{"rendered":"LawnStarter Industry Report"},"content":{"rendered":"<div data-elementor-type=\"wp-page\" data-elementor-id=\"132866\" class=\"elementor elementor-132866\" data-elementor-post-type=\"page\"> \t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-0d39987 elementor-section-full_width elementor-section-height-default elementor-section-height-default\" data-id=\"0d39987\" data-element_type=\"section\" data-e-type=\"section\"> \t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\"> \t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-3639215\" data-id=\"3639215\" data-element_type=\"column\" data-e-type=\"column\"> \t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\"> \t\t\t\t\t\t<div class=\"elementor-element elementor-element-df9e3bd elementor-widget elementor-widget-html\" data-id=\"df9e3bd\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\"> \t\t\t\t<div class=\"elementor-widget-container\"> \t\t\t\t\t<!DOCTYPE html> <html lang=\"en\"> <head> <meta charset=\"UTF-8\"> <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"> <title>The State of Lawn Care in America: 2025 \u2014 LawnStarter<\/title> <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js@4.4.0\/dist\/chart.umd.min.js\"><\/script> <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chartjs-plugin-annotation@3.0.1\/dist\/chartjs-plugin-annotation.min.js\"><\/script> <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/d3@7\/dist\/d3.min.js\"><\/script> <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/topojson-client@3\/dist\/topojson-client.min.js\"><\/script> <style> :root{   --g1:#0D2818;--g2:#1B4332;--g3:#2D6A4F;--g4:#52B788;--g5:#95D5B2;--g6:#D8F3DC;   --orange:#E76F51;--yellow:#F4A261;--teal:#00B4D8;--purple:#7B2D8B;--red:#E63946;   --blue:#1D3557;--cream:#FAFAF5;--white:#fff;--gray:#F2F2EE;--mid:#666;--dark:#1a1a1a;   --r:14px;--shadow:0 4px 24px rgba(0,0,0,.08); } *{box-sizing:border-box;margin:0;padding:0} body{font-family:'Georgia',serif;background:var(--cream);color:var(--dark);line-height:1.6;font-size:16px} a{color:inherit}  \/* HERO *\/ .hero{background:linear-gradient(155deg,#040f08 0%,#0d2818 45%,#1b4332 100%);color:#fff;padding:80px 40px 100px;text-align:center;position:relative;overflow:hidden} .hero-eyebrow{font-size:16px;font-weight:700;letter-spacing:5px;text-transform:uppercase;color:#ffffff;margin-bottom:24px;font-family:'Courier New',monospace} .hero h1{font-size:clamp(36px,5.5vw,72px);font-weight:700;line-height:1.05;margin-bottom:16px;letter-spacing:-1px} .hero h1 em{color:var(--g4);font-style:normal} .hero-sub{font-size:18px;color:rgba(255,255,255,.6);max-width:600px;margin:0 auto 52px;line-height:1.7} .hero-pills{display:flex;justify-content:center;flex-wrap:wrap;gap:10px;margin-bottom:52px} .pill{background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.12);border-radius:100px;padding:9px 20px;font-size:13px;color:rgba(255,255,255,.75)} .pill strong{color:#fff;font-size:15px} .hero-wave{position:absolute;bottom:-1px;left:0;width:100%;line-height:0} .particles{position:absolute;inset:0;overflow:hidden;pointer-events:none} .p{position:absolute;border-radius:50%;background:rgba(82,183,136,.12);animation:fl 10s ease-in-out infinite} @keyframes fl{0%,100%{transform:translateY(0) scale(1)}50%{transform:translateY(-24px) scale(1.06)}}  \/* LAYOUT *\/ .section{max-width:1140px;margin:0 auto;padding:48px 24px} .section-tag{font-size:16px;font-weight:700;letter-spacing:4px;text-transform:uppercase;color:var(--g3);margin-bottom:10px;font-family:'Courier New',monospace} h2{font-size:clamp(24px,3.5vw,44px);line-height:1.15;margin-bottom:14px;color:var(--g2);font-weight:700;letter-spacing:-0.5px} .lead{font-size:17px;color:var(--mid);max-width:700px;margin-bottom:44px;line-height:1.75}  \/* BANDS *\/ .band{padding:48px 0} .band-dark{background:linear-gradient(160deg,#040f08,#0d2818);color:#fff} .band-dark h2{color:var(--g5)} .band-dark .section-tag{color:var(--g4)} .band-dark .lead{color:rgba(255,255,255,.6)} .band-green{background:linear-gradient(160deg,#f0fff8,#fafaf5)} .band-orange{background:linear-gradient(160deg,#fff8f5,#fafaf5)} .band-teal{background:linear-gradient(160deg,#f0faff,#fafaf5)} .band-purple{background:linear-gradient(160deg,#f8f0ff,#fafaf5)} .band-slate{background:linear-gradient(160deg,#f0f4f8,#fafaf5)}  \/* STAT CARDS *\/ .cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:16px;margin-bottom:48px} .btn-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin:28px 0} @media(max-width:780px){.btn-grid{grid-template-columns:1fr 1fr}} @media(max-width:480px){.btn-grid{grid-template-columns:1fr}} .btn-stat{border-radius:14px;padding:16px 18px;display:flex;flex-direction:row;align-items:center;gap:16px;box-shadow:0 3px 14px rgba(0,0,0,.08);transition:transform .2s,box-shadow .2s;min-height:90px} .btn-stat:hover{transform:translateY(-4px);box-shadow:0 10px 28px rgba(0,0,0,.13)} .btn-stat.cat-price{background:linear-gradient(135deg,#f0faf4 0%,#fff 60%);border:1px solid #c7f0d3} .btn-stat.cat-tip{background:linear-gradient(135deg,#fef4ec 0%,#fff 60%);border:1px solid #fde0c5} .btn-stat.cat-weather{background:linear-gradient(135deg,#eff6ff 0%,#fff 60%);border:1px solid #dbeafe} .btn-stat.cat-schedule{background:linear-gradient(135deg,#f5f3ff 0%,#fff 60%);border:1px solid #ede9f5} .btn-stat.cat-season{background:linear-gradient(135deg,#f0fdf4 0%,#fff 60%);border:1px solid #bbf7d0} .btn-illus{width:70px;height:70px;border-radius:20px;display:flex;align-items:center;justify-content:center;flex-shrink:0;position:relative} .cat-price .btn-illus{background:linear-gradient(145deg,#b7e4c7,#40916c)} .cat-tip .btn-illus{background:linear-gradient(145deg,#fddcb5,#e07c3a)} .cat-weather .btn-illus{background:linear-gradient(145deg,#bfdbfe,#3b82f6)} .cat-schedule .btn-illus{background:linear-gradient(145deg,#ddd6fe,#7c3aed)} .cat-season .btn-illus{background:linear-gradient(145deg,#bbf7d0,#166534)} .bi-m{font-size:34px;line-height:1;display:block;filter:drop-shadow(0 1px 2px rgba(0,0,0,.15))} .bi-a{font-size:18px;position:absolute;bottom:-6px;right:-8px;filter:drop-shadow(0 1px 3px rgba(0,0,0,.3))} .btn-text{flex:1;text-align:left} .btn-num{font-size:clamp(19px,2vw,25px);font-weight:800;color:var(--g1);line-height:1.1;letter-spacing:-0.5px} .btn-label{font-size:11.5px;color:var(--mid);margin-top:4px;line-height:1.4;font-weight:500} .card{background:var(--white);border-radius:var(--r);padding:24px 20px;box-shadow:var(--shadow);border-top:4px solid var(--g4);transition:transform .2s,box-shadow .2s} .card:hover{transform:translateY(-4px);box-shadow:0 12px 36px rgba(0,0,0,.12)} .card.c-o{border-color:var(--orange)}.card.c-y{border-color:var(--yellow)}.card.c-t{border-color:var(--teal)}.card.c-p{border-color:var(--purple)}.card.c-r{border-color:var(--red)}.card.c-b{border-color:var(--blue)} .card-label{font-size:13px;font-weight:700;letter-spacing:2px;text-transform:uppercase;color:var(--mid);margin-bottom:8px;font-family:'Courier New',monospace} .card-num{font-size:clamp(28px,3vw,40px);font-weight:700;color:var(--g2);line-height:1;letter-spacing:-1px} .card-sub{font-size:13px;color:var(--mid);margin-top:8px}  \/* CHART WRAP *\/ .chart-box{background:var(--white);border-radius:var(--r);padding:32px;box-shadow:var(--shadow);margin-bottom:28px} .chart-box h3{font-size:20px;font-weight:700;color:var(--g2);margin-bottom:6px} .chart-box .note{font-size:13px;color:var(--mid);margin-bottom:24px} .grid2{display:grid;grid-template-columns:1fr 1fr;gap:24px} @media(max-width:720px){.grid2{grid-template-columns:1fr}}  \/* CALLOUTS *\/ .callout{border-radius:var(--r);padding:28px 32px;margin:28px 0;display:flex;gap:20px;align-items:flex-start} .callout-icon{font-size:40px;flex-shrink:0;line-height:1} .callout h4{font-size:18px;font-weight:700;margin-bottom:8px} .callout p{font-size:14px;line-height:1.7} .c-green{background:var(--g2);color:#fff}.c-green h4{color:var(--g5)} .c-green p{color:rgba(255,255,255,.75)} .c-orange{background:linear-gradient(135deg,#b03a2e,#e76f51);color:#fff}.c-orange h4{color:#ffe8e0}.c-orange p{color:rgba(255,255,255,.85)} .c-teal{background:linear-gradient(135deg,#0077b6,#00b4d8);color:#fff}.c-teal h4{color:#caf0f8}.c-teal p{color:rgba(255,255,255,.85)} .c-purple{background:linear-gradient(135deg,#4a0072,#7b2d8b);color:#fff}.c-purple h4{color:#e9d5f5}.c-purple p{color:rgba(255,255,255,.85)} .c-amber{background:linear-gradient(135deg,#b45309,#f4a261);color:#fff}.c-amber h4{color:#fff3e0}.c-amber p{color:rgba(255,255,255,.9)}  \/* VERSUS CARD *\/ .vs-card{display:grid;grid-template-columns:1fr auto 1fr;background:var(--white);border-radius:var(--r);box-shadow:var(--shadow);overflow:hidden;margin:28px 0} .vs-side{padding:32px;text-align:center} .vs-side.left{background:linear-gradient(135deg,#f0fff8,#fff)} .vs-side.right{background:linear-gradient(135deg,#fff8f5,#fff)} .vs-label{font-size:11px;letter-spacing:2px;text-transform:uppercase;color:var(--mid);margin-bottom:10px;font-family:'Courier New',monospace} .vs-num{font-size:clamp(36px,4vw,52px);font-weight:700;line-height:1;letter-spacing:-2px} .vs-sub{font-size:14px;color:var(--mid);margin-top:8px} .vs-divider{background:var(--gray);display:flex;align-items:center;justify-content:center;padding:0 20px;font-size:11px;letter-spacing:3px;text-transform:uppercase;color:var(--mid);writing-mode:vertical-rl;font-family:'Courier New',monospace} @media(max-width:500px){.vs-card{grid-template-columns:1fr;grid-template-rows:auto auto auto}.vs-divider{writing-mode:initial;padding:14px;text-align:center}}  \/* ZIP TABLE *\/ .zip-table{width:100%;border-collapse:collapse;font-size:14px;margin-top:20px} .zip-table th{text-align:left;padding:10px 14px;background:var(--g2);color:var(--g5);font-size:11px;letter-spacing:2px;text-transform:uppercase;font-weight:600;font-family:'Courier New',monospace} .zip-table td{padding:10px 14px;border-bottom:1px solid #f0f0ea} .zip-table tr:hover td{background:#f8f8f4} .tag-high{background:#fff0f0;color:#c0392b;padding:3px 10px;border-radius:100px;font-size:12px;font-weight:700} .tag-low{background:#f0fff4;color:#1b4332;padding:3px 10px;border-radius:100px;font-size:12px;font-weight:700}  \/* DISPUTE BARS *\/ .dispute-list{list-style:none;margin-top:20px} .dispute-item{display:flex;align-items:center;gap:12px;padding:10px 0;border-bottom:1px solid #f0f0ea} .dispute-item:last-child{border:none} .dispute-label{font-size:13px;min-width:200px} .dispute-bar-wrap{flex:1;height:8px;background:#f0f0ea;border-radius:4px;overflow:hidden} .dispute-bar{height:8px;border-radius:4px} .dispute-pct{font-size:13px;font-weight:700;min-width:45px;text-align:right}  \/* BEST VALUE GRID *\/ .value-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:16px;margin-top:28px} .vc{background:var(--white);border-radius:var(--r);padding:20px;box-shadow:var(--shadow);border-left:4px solid var(--g4)} .vc-city{font-size:17px;font-weight:700;color:var(--g2);margin-bottom:2px} .vc-state{font-size:11px;color:var(--mid);text-transform:uppercase;letter-spacing:1px;margin-bottom:10px} .vc-price{font-size:28px;font-weight:700;color:var(--orange);line-height:1} .vc-mows{font-size:13px;color:var(--mid);margin-top:4px} .vc-stat{font-size:12px;color:var(--mid);margin-top:6px;display:flex;align-items:center;gap:6px} .vc-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}  .map-legend{display:flex;flex-wrap:wrap;gap:20px;font-size:13px;color:var(--mid)} .ld{width:12px;height:12px;border-radius:50%;display:inline-block;margin-right:5px;vertical-align:middle}  \/* MONTH CHART WRAPPER *\/ .month-grid{display:grid;grid-template-columns:repeat(12,1fr);gap:6px;margin-top:24px} .month-bar-wrap{text-align:center} .month-bar-bg{background:#f0f0ea;border-radius:6px 6px 0 0;position:relative;overflow:hidden;height:140px;display:flex;align-items:flex-end} .month-bar-fill{width:100%;border-radius:4px 4px 0 0;transition:height .8s ease} .month-label{font-size:10px;color:var(--mid);margin-top:6px;font-family:'Courier New',monospace;text-transform:uppercase} .month-val{font-size:10px;font-weight:700;color:var(--g2);margin-top:2px}  \/* FADE *\/ .fade{opacity:0;transform:translateY(28px);transition:opacity .7s,transform .7s} .fade.vis{opacity:1;transform:none}  \/* FOOTER *\/ footer{background:var(--g1);color:rgba(255,255,255,.45);text-align:center;padding:40px 24px;font-size:13px} footer strong{color:var(--g4)}  \/* MOBILE: scatter chart stops scaling down (text becomes unreadable below ~600px viewport).    Pin SVG to native width and let the container scroll horizontally. *\/ @media(max-width:720px){   #scatterChart{overflow-x:auto;-webkit-overflow-scrolling:touch;margin:0 -16px;padding:0 16px 8px}   #scatterChart > svg{width:760px!important;min-width:760px;max-width:none}   #scatterChart::after{content:'\\2190 swipe to see the full chart \\2192';display:block;font-size:11px;color:var(--mid);text-align:center;margin-top:6px;font-family:'Courier New',monospace;letter-spacing:.5px} } <\/style> <\/head> <body>  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 HERO \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 --> <div class=\"hero\">   <div class=\"particles\">     <div class=\"p\" style=\"width:100px;height:100px;top:12%;left:6%;animation-delay:0s\"><\/div>     <div class=\"p\" style=\"width:60px;height:60px;top:65%;left:4%;animation-delay:2s\"><\/div>     <div class=\"p\" style=\"width:140px;height:140px;top:18%;right:5%;animation-delay:1s\"><\/div>     <div class=\"p\" style=\"width:70px;height:70px;top:72%;right:8%;animation-delay:3s\"><\/div>     <div class=\"p\" style=\"width:50px;height:50px;top:42%;left:18%;animation-delay:4s\"><\/div>     <div class=\"p\" style=\"width:90px;height:90px;top:80%;left:55%;animation-delay:1.5s\"><\/div>   <\/div>   <p class=\"hero-eyebrow\">LawnStarter Internal Data &bull; Full Year 2025<\/p>   <h1>The State of <em>Lawn Care<\/em><br>in America: 2025<\/h1>   <p class=\"hero-sub\">From 2M+ mows across 2K+ cities \u2014 the most comprehensive look at how America maintains its lawns.<\/p>   <div class=\"hero-pills\">     <span class=\"pill\"><strong>2M+<\/strong> mows analyzed<\/span>     <span class=\"pill\"><strong>2K+<\/strong> cities<\/span>     <span class=\"pill\">Avg mow: <strong>$53.59<\/strong><\/span>     <span class=\"pill\">Prices up <strong>+6.6%<\/strong> YoY<\/span>     <span class=\"pill\">Peak day: <strong>July 3<\/strong> \u2014 12,050 mows<\/span>     <span class=\"pill\">Biweekly is king: <strong>72.9%<\/strong> of all mows<\/span>   <\/div>   <div class=\"hero-wave\"><svg viewbox=\"0 0 1440 70\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M0,70 C480,0 960,60 1440,20 L1440,70 Z\" fill=\"#FAFAF5\"\/><\/svg><\/div> <\/div>  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 NATIONAL SNAPSHOT \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 --> <div class=\"band band-green\"> <section id=\"national-snapshot\" class=\"section fade\">   <p class=\"section-tag\">2025 National Snapshot<\/p>   <h2>The Year in Numbers<\/h2>   <p class=\"lead\">What do professional lawn care services actually cost? LawnStarter crunched 2+ million mows across 2K+ cities \u2014 here's what the data reveals.<\/p>   <div class=\"cards\">     <div class=\"card c-y\"><div class=\"card-label\">Avg Annual Lawn Care Spending<\/div><div class=\"card-num\">$407\/yr<\/div><div class=\"card-sub\"><strong>national average<\/strong> \u2014 $6.38 per 1,000 sq ft per mow across 2K+ cities<\/div><\/div>     <div class=\"card c-o\"><div class=\"card-label\">Priciest Market<\/div><div class=\"card-num\">$576\/yr<\/div><div class=\"card-sub\"><strong>Orlando, Florida<\/strong> \u2014 an 11-month mowing season drives the <strong>highest annual cost<\/strong> among tracked cities<\/div><\/div>     <div class=\"card c-b\"><div class=\"card-label\">Most Affordable<\/div><div class=\"card-num\">$258\/yr<\/div><div class=\"card-sub\"><strong>Detroit, Michigan<\/strong> \u2014 cold winters mean a short mowing season keeps annual costs the lowest in the nation<\/div><\/div>     <div class=\"card c-t\"><div class=\"card-label\">Biggest Tipper City<\/div><div class=\"card-num\">51.6%<\/div><div class=\"card-sub\"><strong>Amarillo, Texas<\/strong> \u2014 tips on more than half of all mows<\/div><\/div>     <div class=\"card c-p\"><div class=\"card-label\">Peak Mow Day<\/div><div class=\"card-num\">12,050<\/div><div class=\"card-sub\"><strong>mows in a single day<\/strong> \u2014 July 3, 2025<\/div><\/div>     <div class=\"card\"><div class=\"card-label\">Longest Mowing Season<\/div><div class=\"card-num\">11 months<\/div><div class=\"card-sub\"><strong>Florida, Texas, &amp; Louisiana<\/strong> mow nearly year-round \u2014 <strong>Minnesota<\/strong> gets just 6 months<\/div><\/div>     <div class=\"card c-r\"><div class=\"card-label\">Price Gap by ZIP Code<\/div><div class=\"card-num\">$38<\/div><div class=\"card-sub\">In <strong>Los Angeles<\/strong>, the cheapest and most expensive ZIP codes are $38 apart \u2014 same city, same mow, wildly different price<\/div><\/div>   <\/div> <\/section> <\/div>  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 SEASONAL CHART \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 --> <section id=\"seasonal\" class=\"section fade\">   <p class=\"section-tag\">Seasonal Patterns<\/p>   <h2>The Lawn Care Calendar: Summer is Everything<\/h2>   <p class=\"lead\">July is peak mow month. January barely exists. The industry runs on a 9-month active season \u2014 March through November \u2014 with a 3-month winter shutdown in December, January, and February.<\/p>   <div class=\"chart-box\">     <h3>Monthly Mow Volume \u2014 2025<\/h3>     <p class=\"note\">Total completed mowing jobs by month. December\u2013February = off-season. March &amp; November = shoulder months. April\u2013October = peak mowing season.<\/p>     <canvas id=\"monthlyChart\" height=\"200\"><\/canvas>   <\/div>   <div class=\"grid2\">     <div class=\"callout c-green\">       <div class=\"callout-icon\">\ud83d\udcc8<\/div>       <div>         <h4>July is 6.5X busier than January<\/h4>         <p>Peak summer demand dwarfs the off-season by more than 6X \u2014 a volume surge that hits like clockwork, every year.<\/p>       <\/div>     <\/div>     <div class=\"callout c-amber\">       <div class=\"callout-icon\">\ud83d\udcb0<\/div>       <div>         <h4>Prices rise with the temperature<\/h4>         <p>Average price per mow climbs from $49.28 in January to $54.66 in August \u2014 a 10.9% premium just for being peak season. Prices per mow also rose +6.6% year-over-year vs. 2024. Demand-side pricing at work.<\/p>       <\/div>     <\/div>   <\/div> <\/section>  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 SEASON LENGTH \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 --> <div class=\"band band-teal\"> <section id=\"season-length\" class=\"section fade\">   <p class=\"section-tag\">Climate &amp; Season<\/p>   <h2>Florida Mows Nearly Year-Round. Minnesota's Season Wraps Up by October.<\/h2>   <p class=\"lead\">Your latitude determines your lawn care calendar. Gulf and Pacific Coast states run near-year-round. Upper Midwest and New England states race through a brief warm-weather window. The difference reshapes what homeowners spend and how pros plan their business.<\/p>   <div class=\"chart-box\">     <h3>Mowing Season Length by State \u2014 2025<\/h3>     <p class=\"note\">Based on 2025 completion data. Darker = longer active season. <strong>National average: 8 months.<\/strong><\/p>     <div id=\"seasonMap\" style=\"max-width:900px;margin:16px auto 8px\"><\/div>     <div class=\"map-legend\" style=\"max-width:900px;margin:0 auto\">       <span><span class=\"ld\" style=\"background:#d8f3dc\"><\/span>Brief \u2013 6 months<\/span>       <span><span class=\"ld\" style=\"background:#95d5b2\"><\/span>Short \u2013 7 months<\/span>       <span><span class=\"ld\" style=\"background:#52b788\"><\/span>Mid \u2013 8 months<\/span>       <span><span class=\"ld\" style=\"background:#2d6a4f\"><\/span>Long \u2013 9 months<\/span>       <span><span class=\"ld\" style=\"background:#1b4332\"><\/span>Extended \u2013 10 months<\/span>       <span><span class=\"ld\" style=\"background:#0a2e1a\"><\/span>~Year \u2013 11\u201312 months<\/span>     <\/div>   <\/div>   <div class=\"grid2\" style=\"margin-top:16px\">     <div class=\"callout c-green\">       <div class=\"callout-icon\">\ud83c\udf34<\/div>       <div>         <h4>The South &amp; Gulf Coast: near-year-round mowing<\/h4>         <p><strong>Florida<\/strong> mows nearly every month of the year. <strong>Texas's<\/strong> long warm corridors, <strong>Louisiana's<\/strong> Gulf humidity, and <strong>Washington, D.C.'s<\/strong> mild winters keep lawns growing well into late fall. Homeowners in these states pay for lawn care almost continuously \u2014 and pros build their businesses around steady, uninterrupted demand.<\/p>       <\/div>     <\/div>     <div class=\"callout c-teal\">       <div class=\"callout-icon\">\u2744\ufe0f<\/div>       <div>         <h4>The Brief-Season States: 6 Months to Make It Work<\/h4>         <p><strong>Minnesota<\/strong>, <strong>Vermont<\/strong>, <strong>New Hampshire<\/strong>, <strong>Montana<\/strong>, and <strong>Wyoming<\/strong> all run just 6 months \u2014 the shortest mowing seasons in the country. Pros in these markets compress a full year's revenue into a sprint, which drives prices well above the national average despite lower year-round demand.<\/p>       <\/div>     <\/div>   <\/div> <\/section> <\/div>  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 DAY OF WEEK \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 --> <div class=\"band band-slate\"> <section id=\"scheduling\" class=\"section fade\">   <p class=\"section-tag\">Scheduling Behavior<\/p>   <h2>Thursday is America's Lawn Day<\/h2>   <p class=\"lead\">Thursday leads the week \u2014 but Wednesday is right behind it at 16.8%. All five weekdays cluster tightly between 15% and 17%. The real drop-off is the weekend: Saturday falls to 10.8% and Sunday bottoms out at just 7.2%.<\/p>   <div class=\"grid2\">     <div class=\"chart-box\">       <h3>Share of Mows by Day of Week \u2014 2025<\/h3>       <p class=\"note\">Completed mowing jobs, 2025<\/p>       <canvas id=\"dowChart\" height=\"260\"><\/canvas>     <\/div>     <div style=\"display:flex;flex-direction:column;gap:16px;justify-content:center\">       <div class=\"callout c-teal\">         <div class=\"callout-icon\">\ud83d\udcc5<\/div>         <div>           <h4>Mon\u2013Fri handle 82.1% of all mows<\/h4>           <p>Weekdays dominate. Saturday adds 10.7%. Sunday is the industry's day off at just 7.2% \u2014 the lightest day despite homeowners being home.<\/p>         <\/div>       <\/div>       <div class=\"callout c-orange\">         <div class=\"callout-icon\">\ud83d\uddd3<\/div>         <div>           <h4>Wednesday nearly matches Thursday<\/h4>           <p>Mon\u2013Fri all land between 15.2% and 16.9%. Thursday leads at 16.9%, Wednesday follows at 16.8% \u2014 just 0.1 points behind, with Friday close at 16.7%. Then Saturday falls sharply to 10.8% and Sunday bottoms out at 7.2%. The five-day work week is real for pros.<\/p>         <\/div>       <\/div>     <\/div>   <\/div> <\/section> <\/div>  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 MOWING FREQUENCY \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 --> <section id=\"frequency\" class=\"section fade\">   <p class=\"section-tag\">Service Patterns<\/p>   <h2>America Mows Biweekly \u2014 By a Landslide<\/h2>   <p class=\"lead\">72.9% of all lawn mowing in 2025 runs on a biweekly schedule. Weekly customers are the power users. Monthly is more common than most assume.<\/p>   <div class=\"grid2\">     <div class=\"chart-box\" style=\"display:flex;flex-direction:column;align-items:center\">       <h3>Mowing Frequency Distribution<\/h3>       <p class=\"note\" style=\"text-align:center\">Share of 2025 mowing jobs by service frequency<\/p>       <canvas id=\"freqDonut\" width=\"300\" height=\"300\" style=\"max-width:300px\"><\/canvas>     <\/div>     <div style=\"display:flex;flex-direction:column;gap:16px;justify-content:center\">       <div class=\"callout c-purple\">         <div class=\"callout-icon\">\ud83d\udcc6<\/div>         <div>           <h4>Biweekly dominates at 72.9%<\/h4>           <p>Roughly 3 in 4 mows run every 8\u201321 days. This is the industry standard \u2014 enough time for meaningful growth, short enough to stay manageable. It's also the most profitable frequency for pros.<\/p>         <\/div>       <\/div>       <div class=\"callout c-amber\">         <div class=\"callout-icon\">\u26a1<\/div>         <div>           <h4>Weekly customers keep lawns show-ready year-round<\/h4>           <p>13.2% of customers choose weekly mowing \u2014 a pristine, perfectly manicured lawn every single week. Meanwhile 13.9% mow monthly or less, typically for basic upkeep or seasonal properties.<\/p>         <\/div>       <\/div>     <\/div>   <\/div> <\/section>  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 WEATHER DISRUPTION \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 --> <section id=\"weather\" class=\"section fade\">   <p class=\"section-tag\">Weather Impact<\/p>   <h2>The Most Weather-Disrupted Lawn Care Markets<\/h2>   <p class=\"lead\">Weather disrupts 1 in 10 mows in some states \u2014 and less than 1 in 30 in others. Here's where rain, wind, and storms cost homeowners and pros the most lost appointments.<\/p>   <div class=\"chart-box\">     <h3>Weather Disruption Rate by State \u2014 2025<\/h3>     <p class=\"note\">Based on 2025 mowing jobs. Darker = more weather-related disruptions. <strong>National average: ~5.7% disruption rate.<\/strong><\/p>     <div id=\"weatherMap\" style=\"max-width:900px;margin:16px auto 8px\"><\/div>     <div class=\"map-legend\" style=\"max-width:900px;margin:0 auto\">       <span><span class=\"ld\" style=\"background:#d8f3dc\"><\/span>Rarely disrupted (&lt;3%)<\/span>       <span><span class=\"ld\" style=\"background:#52b788\"><\/span>Occasionally (3\u20135%)<\/span>       <span><span class=\"ld\" style=\"background:#f4a261\"><\/span>Frequently (5\u20137%)<\/span>       <span><span class=\"ld\" style=\"background:#e76f51\"><\/span>Often (7\u20139%)<\/span>       <span><span class=\"ld\" style=\"background:#e63946\"><\/span>Highly disrupted (9%+)<\/span>     <\/div>   <\/div>   <div class=\"grid2\" style=\"margin-top:16px\">     <div class=\"callout c-orange\">       <div class=\"callout-icon\">\ud83c\udf27\ufe0f<\/div>       <div>         <h4>Connecticut and Alabama: Weather-Disruption Hotspots<\/h4>         <p>Weather disruption clusters in two distinct regions: <strong>Connecticut<\/strong> leads nationally at 10.89%, joined by the Mid-Atlantic states, where coastal storms and nor'easters routinely interrupt service. Meanwhile, Gulf moisture drives high disruption across the South \u2014 <strong>Alabama<\/strong> (9.49%), <strong>Arkansas<\/strong> (8.95%), and <strong>Tennessee<\/strong> (8.53%) all rank among the most weather-affected states in the country.<\/p>       <\/div>     <\/div>     <div class=\"callout c-green\">       <div class=\"callout-icon\">\u2600\ufe0f<\/div>       <div>         <h4>Desert Southwest &amp; Pacific Northwest: reliably on schedule<\/h4>         <p><strong>New Mexico's<\/strong> arid climate means mows almost always happen as planned. <strong>South Dakota's<\/strong> dry plains and <strong>Oregon's<\/strong> predictable patterns keep disruptions rare too. If you want a dependable lawn care schedule, the desert Southwest is hard to beat.<\/p>       <\/div>     <\/div>   <\/div> <\/section>  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 REGIONAL PRICING \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 --> <section id=\"regional\" class=\"section fade\">   <p class=\"section-tag\">Regional Breakdown<\/p>   <h2>The Northeast Pays the Most. The West Pays the Least.<\/h2>   <p class=\"lead\">Regional geography drives pricing more than any other single factor. The Northeast averages $58.17 per mow \u2014 14% above the West's $50.90. <strong>California<\/strong>, <strong>Arizona<\/strong>, and <strong>New Mexico<\/strong> pull the West's average down sharply despite <strong>Seattle<\/strong> and <strong>Denver's<\/strong> elevated prices.<\/p>   <div class=\"chart-box\" style=\"max-width:600px;margin:0 auto 28px\">     <h3>Average Mow Price by U.S. Region \u2014 2025<\/h3>     <p class=\"note\">Weighted state averages grouped by census region (avg price\/mow by state)<\/p>     <canvas id=\"regionChart\" height=\"220\"><\/canvas>   <\/div>   <div class=\"grid2\" style=\"margin-top:4px\">     <div class=\"callout c-orange\">       <div class=\"callout-icon\">\ud83d\uddfa<\/div>       <div>         <h4>Northeast: $58.17 avg per mow \u2014 America's priciest region<\/h4>         <p>CT ($63.74) \u2192 NH ($63.22) \u2192 MA ($61.91) \u2192 NJ ($60.04). 6 of the 7 Northeast states exceed the national average. High labor costs, shorter growing seasons, and wealthier suburbs create a perfect storm of premium pricing.<\/p>       <\/div>     <\/div>     <div class=\"callout c-teal\">       <div class=\"callout-icon\">\ud83c\udf35<\/div>       <div>         <h4>West: $50.90 avg per mow \u2014 most affordable, surprisingly<\/h4>         <p>Despite <strong>Seattle<\/strong> ($55.71) and <strong>Denver<\/strong> ($54.23), average costs out West are brought down by <strong>California<\/strong> ($45.27), <strong>Arizona<\/strong> ($45.08), and <strong>New Mexico<\/strong> ($45.05) \u2014 3 of the 4 cheapest states for lawn mowing in America.<\/p>       <\/div>     <\/div>   <\/div> <\/section>  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 STATE PRICING \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 --> <div class=\"band band-orange\"> <section id=\"state-pricing\" class=\"section fade\">   <p class=\"section-tag\">Geography of Price<\/p>   <h2>Vermont Pays 75% More Than Arizona<\/h2>   <p class=\"lead\">When it comes to the cost of a mow, a $33.07 gap separates the most expensive state from the cheapest \u2014 Vermont at $78.15 compared with Arizona at $45.08.<\/p>   <div class=\"chart-box\">     <h3>Average Price per Mow by State \u2014 2025<\/h3>     <p class=\"note\">Based on 2025 completed mows. Most states 500+ jobs; smaller markets (AK, HI, VT, WY) included where sufficient data exists. MT excluded \u2014 insufficient volume. <strong>National average: $53.59 per mow.<\/strong><\/p>     <div id=\"statePriceMap\" style=\"max-width:900px;margin:16px auto 8px\"><\/div>     <div class=\"map-legend\" style=\"max-width:900px;margin:0 auto\">       <span><span class=\"ld\" style=\"background:#2d6a4f\"><\/span>Under $50<\/span>       <span><span class=\"ld\" style=\"background:#52b788\"><\/span>$50\u2013$54<\/span>       <span><span class=\"ld\" style=\"background:#f4a261\"><\/span>$54\u2013$58<\/span>       <span><span class=\"ld\" style=\"background:#e76f51\"><\/span>$58\u2013$62<\/span>       <span><span class=\"ld\" style=\"background:#e63946\"><\/span>Over $62<\/span>     <\/div>   <\/div>   <div class=\"vs-card\">     <div class=\"vs-side left\">       <div class=\"vs-label\">Most Expensive State<\/div>       <div class=\"vs-num\" style=\"color:var(--orange)\">$78.15<\/div>       <div style=\"font-size:20px;font-weight:700;color:var(--g2);margin-top:8px\">Vermont<\/div>       <div class=\"vs-sub\">Also: ME $76.27 \u00b7 CT $64.62 \u00b7 NH $64.00<\/div>     <\/div>     <div class=\"vs-divider\">vs<\/div>     <div class=\"vs-side right\">       <div class=\"vs-label\">Cheapest State<\/div>       <div class=\"vs-num\" style=\"color:var(--g3)\">$45.08<\/div>       <div style=\"font-size:20px;font-weight:700;color:var(--g2);margin-top:8px\">Arizona<\/div>       <div class=\"vs-sub\">Also: NM $45.30 \u00b7 CA $45.73 \u00b7 TX $50.33<\/div>     <\/div>   <\/div>   <div class=\"grid2\" style=\"margin-top:16px\">     <div class=\"callout c-purple\">       <div class=\"callout-icon\">\ud83c\udfd4<\/div>       <div>         <h4>Why Vermont tops the chart at $78.15<\/h4>         <p>Vermont\u2019s high prices reflect large rural properties with expansive yards, limited contractor competition in a sparse market, and a compressed 6-month season that pushes pros to charge premium rates to cover annual overhead.<\/p>       <\/div>     <\/div>     <div class=\"callout c-teal\">       <div class=\"callout-icon\">\ud83c\udf35<\/div>       <div>         <h4>Why Arizona bottoms out at $45.08<\/h4>         <p>Arizona\u2019s desert climate has driven a major shift away from traditional grass lawns. Water restrictions and xeriscaping trends mean fewer properties need regular mowing \u2014 those that do tend to be smaller suburban patches. Combined with fierce contractor competition in Phoenix and Tucson, prices settle at the nation\u2019s lowest.<\/p>       <\/div>     <\/div>   <\/div>    <div id=\"price-per-sqft\" class=\"chart-box\" style=\"margin-top:28px\">     <h3>The States Where Mowing Costs Jumped Most: 2024 to 2025<\/h3>     <p class=\"note\">City-level methodology: avg price \u00f7 avg yard size per city, aggregated to state. Only cities with sufficient completed mows in both years included. <strong>National average: +4.8% year-over-year.<\/strong> Montana, Hawaii, Alaska, Wyoming, and South Dakota excluded due to insufficient volume or single-city coverage.<\/p>     <div id=\"stateP1kChangeMap\" style=\"max-width:900px;margin:16px auto 8px\"><\/div>     <div class=\"map-legend\" style=\"max-width:900px;margin:0 auto\">       <span><span class=\"ld\" style=\"background:#a8dadc\"><\/span>Under +3%<\/span>       <span><span class=\"ld\" style=\"background:#52b788\"><\/span>+3%\u2013+6%<\/span>       <span><span class=\"ld\" style=\"background:#f4a261\"><\/span>+6%\u2013+9%<\/span>       <span><span class=\"ld\" style=\"background:#e63946\"><\/span>+9% or more<\/span>     <\/div>   <\/div> <\/section> <\/div>  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 TOP MARKETS PRICE \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 --> <section id=\"market-pricing\" class=\"section fade\">   <p class=\"section-tag\">Market Pricing<\/p>   <h2>Southern Markets Are Consistently the Most Affordable, Regardless of Size<\/h2>   <p class=\"lead\"><strong>Atlanta<\/strong>, <strong>Nashville<\/strong>, <strong>Charlotte<\/strong>, <strong>Dallas<\/strong>, and <strong>Houston<\/strong> \u2014 all major metros \u2014 come in well <strong>below the national average<\/strong> of $6.30 per 1,000 sq ft. <strong>Raleigh<\/strong> sits at $5.30, roughly the same as <strong>Knoxville<\/strong>. Market size isn\u2019t the driver here: region is.<\/p>   <div class=\"chart-box\">     <h3>Avg Price per 1,000 sq ft \u2014 Selected Major Markets<\/h3>     <p class=\"note\">Major markets with sufficient data, sorted lowest to highest price per 1,000 sq ft.<\/p>     <canvas id=\"marketPriceChart\" height=\"300\"><\/canvas>   <\/div>   <div class=\"grid2\">     <div class=\"callout c-green\">       <div class=\"callout-icon\">\ud83c\udfc6<\/div>       <div>         <h4>Philadelphia, Pennsylvania: $18.60\/1,000 sq ft \u2014 priciest per square foot<\/h4>         <p><strong>Philadelphia<\/strong> charges $18.60 per 1,000 sq ft \u2014 nearly 3\u00d7 the national average of $6.38. <strong>Washington, D.C.<\/strong> ($17.80) and <strong>Chicago<\/strong> ($15.70) follow. Dense urban lots with small yard sizes drive the per-sq ft rate up sharply even when total job price looks moderate.<\/p>       <\/div>     <\/div>     <div class=\"callout c-teal\">       <div class=\"callout-icon\">\ud83c\udff7<\/div>       <div>         <h4>Knoxville: Most affordable per square foot<\/h4>         <p>$4.80\/1,000 sq ft \u2014 <strong>Knoxville, Tennessee<\/strong>, delivers the lowest per-sq ft rate of all tracked markets. <strong>Raleigh, North Carolina<\/strong> ($5.30), <strong>Atlanta<\/strong> ($5.80), and <strong>Nashville, Tennessee<\/strong> ($5.80) are similarly affordable on a square-foot basis.<\/p>       <\/div>     <\/div>   <\/div>   <div class=\"callout c-purple\" style=\"margin-top:4px\">     <div class=\"callout-icon\">\ud83c\udfdb<\/div>     <div>       <h4>What price per square foot tells you that price per mow doesn\u2019t<\/h4>       <p>A $55 mow in <strong>Chicago<\/strong> covers a tiny 3,400 sq ft lot \u2014 that\u2019s $15.70\/1,000 sq ft. The same $55 in <strong>Nashville<\/strong> covers a 9,500 sq ft yard \u2014 just $5.80\/1,000 sq ft. Per-sq ft pricing reveals true market cost differences that the headline mow price obscures.<\/p>     <\/div>   <\/div>   <div id=\"annual-cost\" class=\"chart-box\" style=\"margin-top:24px\">     <h3>Average Annual Lawn Care Spending by Market \u2014 2025<\/h3>     <p class=\"note\">Annual cost = avg price\/mow \u00d7 avg mows per property per year. <strong>National average: $407\/yr.<\/strong><\/p>     <canvas id=\"annualCostChart\" height=\"240\"><\/canvas>   <\/div>   <div class=\"callout c-amber\" style=\"margin-top:8px\">     <div class=\"callout-icon\">\ud83d\udcb8<\/div>     <div>       <h4>Orlando homeowners spend $576\/year. Detroit spends just $258.<\/h4>       <p>Year-round growing seasons don\u2019t just mean more mows \u2014 they mean $318 more per year. <strong>Orlando<\/strong> homeowners schedule mows across 11 months a year, totaling $576\/yr. <strong>Detroit<\/strong> customers request mows across just a few months a year, totaling $258\/yr. Climate, not price, is the biggest driver of total annual lawn care spend.<\/p>     <\/div>   <\/div> <\/section> <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 BEST VALUE MARKETS \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 --> <section id=\"best-value\" class=\"section fade\">   <p class=\"section-tag\">Best Value Markets<\/p>   <h2>Where Lawn Care Costs the Least per 1,000 sq ft<\/h2>   <p class=\"lead\">Ranked by price per 1,000 square feet, these are the cities where you get the most lawn mowed for the least money. The lower the cost per square foot, the further your budget goes. <strong>National average: $6.38\/1,000 sq ft.<\/strong><\/p>   <div class=\"value-grid\">     <div class=\"vc\"><div class=\"vc-city\">Knoxville<\/div><div class=\"vc-state\">Tennessee<\/div><div class=\"vc-price\">$4.80<span style=\"font-size:14px;font-weight:400;color:var(--mid)\">\/1,000 sq ft<\/span><\/div><div class=\"vc-mows\">Lowest per-sqft rate of any tracked market<\/div><div class=\"vc-stat\"><span class=\"vc-dot\" style=\"background:var(--g4)\"><\/span>$1.79 below national avg\/sq ft<\/div><\/div>     <div class=\"vc\"><div class=\"vc-city\">Raleigh<\/div><div class=\"vc-state\">North Carolina<\/div><div class=\"vc-price\">$5.30<span style=\"font-size:14px;font-weight:400;color:var(--mid)\">\/1,000 sq ft<\/span><\/div><div class=\"vc-mows\">Large yards, competitive Carolinas market<\/div><div class=\"vc-stat\"><span class=\"vc-dot\" style=\"background:var(--g4)\"><\/span>$1.29 below national avg\/sq ft<\/div><\/div>     <div class=\"vc\"><div class=\"vc-city\">Lakeland<\/div><div class=\"vc-state\">Florida<\/div><div class=\"vc-price\">$5.70<span style=\"font-size:14px;font-weight:400;color:var(--mid)\">\/1,000 sq ft<\/span><\/div><div class=\"vc-mows\">Year-round growing season, high volume market<\/div><div class=\"vc-stat\"><span class=\"vc-dot\" style=\"background:var(--g4)\"><\/span>$0.89 below national avg\/sq ft<\/div><\/div>     <div class=\"vc\"><div class=\"vc-city\">Atlanta<\/div><div class=\"vc-state\">Georgia<\/div><div class=\"vc-price\">$5.80<span style=\"font-size:14px;font-weight:400;color:var(--mid)\">\/1,000 sq ft<\/span><\/div><div class=\"vc-mows\">Large lots, suburban growth keeps sqft costs low<\/div><div class=\"vc-stat\"><span class=\"vc-dot\" style=\"background:var(--g4)\"><\/span>$0.79 below national avg\/sq ft<\/div><\/div>     <div class=\"vc\"><div class=\"vc-city\">Nashville<\/div><div class=\"vc-state\">Tennessee<\/div><div class=\"vc-price\">$5.80<span style=\"font-size:14px;font-weight:400;color:var(--mid)\">\/1,000 sq ft<\/span><\/div><div class=\"vc-mows\">Active market with spacious suburban yards<\/div><div class=\"vc-stat\"><span class=\"vc-dot\" style=\"background:var(--g4)\"><\/span>$0.79 below national avg\/sq ft<\/div><\/div>     <div class=\"vc\"><div class=\"vc-city\">Charlotte<\/div><div class=\"vc-state\">North Carolina<\/div><div class=\"vc-price\">$5.90<span style=\"font-size:14px;font-weight:400;color:var(--mid)\">\/1,000 sq ft<\/span><\/div><div class=\"vc-mows\">Fast-growing metro, strong value per square foot<\/div><div class=\"vc-stat\"><span class=\"vc-dot\" style=\"background:var(--g4)\"><\/span>$0.69 below national avg\/sq ft<\/div><\/div>   <\/div> <\/section>  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 ZIP CODE PRICE SHOCK \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 --> <section id=\"zip-pricing\" class=\"section fade\">   <p class=\"section-tag\">ZIP Code Pricing<\/p>   <h2>Same City. Same Mow. Wildly Different Price per Square Foot.<\/h2>   <p class=\"lead\">Within a single city, lawn care prices per square foot can vary dramatically depending on the neighborhood. Suburban ZIP codes consistently run 30\u201360% above urban core ZIPs \u2014 driven by larger lot sizes, not service differences.<\/p>    <div class=\"callout c-orange\" style=\"margin-bottom:20px\">     <div class=\"callout-icon\">\ud83e\udd2f<\/div>     <div>       <h4>In Los Angeles, the same mow costs $38 more depending on your ZIP code<\/h4>       <p><strong>Los Angeles<\/strong> leads all tracked markets with a $38 gap between its cheapest and most expensive ZIP codes. <strong>Glendale, Arizona<\/strong> ($37), <strong>Euless, Texas<\/strong> ($33), and <strong>Woodinville, Washington<\/strong> ($30) aren\u2019t far behind. In many cities, your neighborhood matters as much as your state \u2014 sometimes more.<\/p>     <\/div>   <\/div>    <div class=\"chart-box\">     <h3>Cities with the Widest ZIP Code Price Spread \u2014 2025<\/h3>     <p class=\"note\">Dollar price spread (max ZIP avg minus min ZIP avg per mow). ZIP codes with fewer than 25 completed mows or average yard sizes outside 2,000\u201320,000 sq\u00a0ft excluded; prices filtered to $20\u2013$200.<\/p>     <canvas id=\"zipSpreadChart\" height=\"220\"><\/canvas>   <\/div>    <div class=\"callout c-purple\" style=\"margin-top:32px\">     <div class=\"callout-icon\" style=\"font-size:28px\">\ud83d\udca1<\/div>     <div>       <h4 style=\"font-size:15px\">The rule holds in every city<\/h4>       <p style=\"font-size:13px\">Suburban ZIP codes consistently price 30\u201360% above urban core ZIPs \u2014 driven by larger yard sizes, not service quality. The most variable cities show extreme intra-city gaps that dwarf even state-to-state price differences. Same company. Same mow. Different neighborhood.<\/p>     <\/div>   <\/div> <\/section>  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 TIPPING \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 --> <div class=\"band band-green\"> <section id=\"tipping\" class=\"section fade\">   <p class=\"section-tag\">Tipping Culture<\/p>   <h2>Texas Tips Big: Inside America\u2019s Lawn Care Tipping Culture<\/h2>   <p class=\"lead\">In <strong>Amarillo, Texas<\/strong>, more than half of all lawn care customers tip their pro. In <strong>Orlando<\/strong>, fewer than 1 in 5 do. The <strong>national average sits at 27%<\/strong> \u2014 but that number hides a map of extremes, from Texas generosity to Florida indifference. Which city\u2019s pros actually earn the most in tips per job?<\/p>   <p style=\"font-style:italic;font-size:14px;color:var(--mid);max-width:820px;margin:-28px 0 32px;line-height:1.7\"><em>*LawnStarter matches customer tips for our <a href=\"https:\/\/www.lawnstarter.com\/blog\/lawn-care\/lawn-care-pros\/\" style=\"color:#0077b6;text-decoration:underline\">Platinum-level lawn care pros<\/a> \u2014 our highest-rated providers with the strongest track records of consistent, high-quality work. All LawnStarter pros keep 100% of their tips.<\/em><\/p>   <div style=\"border-left:4px solid var(--g3);padding:8px 18px;margin:0 0 24px;background:linear-gradient(90deg,rgba(240,253,244,.7),transparent);border-radius:0 8px 8px 0\">     <p style=\"font-size:11px;letter-spacing:3px;text-transform:uppercase;color:var(--g3);font-family:'Courier New',monospace;margin-bottom:2px\">Part I<\/p>     <h3 style=\"font-size:22px;color:var(--g2);font-weight:700;margin:0\">Who Tips?<\/h3>   <\/div>   <div class=\"chart-box\" style=\"margin-top:20px;margin-bottom:0\">     <h3 style=\"margin-bottom:4px\">\ud83c\udfc6 Top 10 Tipping Cities \u2014 2025<\/h3>     <p class=\"note\" style=\"margin-bottom:16px\">Highest tip rates nationally among all cities with <strong>500+ completed 2025 mows<\/strong> \u2014 not just the largest metros. Smaller markets with strong tipping cultures dominate this list. <span style=\"display:inline-block;width:10px;height:10px;background:#1b4332;border-radius:2px;vertical-align:middle;margin-right:4px\"><\/span>Texas cities highlighted.<\/p>     <div style=\"display:flex;flex-direction:column;gap:5px\">       <div style=\"display:flex;align-items:center;gap:12px;padding:8px 14px;background:#f0fdf4;border-radius:8px;border:1px solid #bbf7d0\"><span style=\"font-size:16px;font-weight:800;color:#0d2818;width:22px;text-align:right;font-family:'Courier New',monospace\">1<\/span><span style=\"flex:1;font-size:13.5px;font-weight:600;color:var(--dark)\">Amarillo, TX \ud83e\udd47<\/span><div style=\"width:140px;background:#e0e0d8;border-radius:3px;height:7px;overflow:hidden\"><div style=\"width:100.0%;background:#1b4332;height:7px;border-radius:3px\"><\/div><\/div><span style=\"font-size:14px;font-weight:800;color:#0d2818;width:44px;text-align:right\">51.6%<\/span><\/div>       <div style=\"display:flex;align-items:center;gap:12px;padding:8px 14px;background:#f0fdf4;border-radius:8px;border:1px solid #bbf7d0\"><span style=\"font-size:16px;font-weight:800;color:#0d2818;width:22px;text-align:right;font-family:'Courier New',monospace\">2<\/span><span style=\"flex:1;font-size:13.5px;font-weight:600;color:var(--dark)\">McAllen, TX \ud83e\udd48<\/span><div style=\"width:140px;background:#e0e0d8;border-radius:3px;height:7px;overflow:hidden\"><div style=\"width:95.7%;background:#1b4332;height:7px;border-radius:3px\"><\/div><\/div><span style=\"font-size:14px;font-weight:800;color:#0d2818;width:44px;text-align:right\">49.4%<\/span><\/div>       <div style=\"display:flex;align-items:center;gap:12px;padding:8px 14px;background:#f0fdf4;border-radius:8px;border:1px solid #bbf7d0\"><span style=\"font-size:16px;font-weight:800;color:#0d2818;width:22px;text-align:right;font-family:'Courier New',monospace\">3<\/span><span style=\"flex:1;font-size:13.5px;font-weight:600;color:var(--dark)\">Corpus Christi, TX \ud83e\udd49<\/span><div style=\"width:140px;background:#e0e0d8;border-radius:3px;height:7px;overflow:hidden\"><div style=\"width:75.4%;background:#1b4332;height:7px;border-radius:3px\"><\/div><\/div><span style=\"font-size:14px;font-weight:800;color:#0d2818;width:44px;text-align:right\">38.9%<\/span><\/div>       <div style=\"display:flex;align-items:center;gap:12px;padding:8px 14px;background:#f0fdf4;border-radius:8px;border:1px solid #bbf7d0\"><span style=\"font-size:16px;font-weight:800;color:#0d2818;width:22px;text-align:right;font-family:'Courier New',monospace\">4<\/span><span style=\"flex:1;font-size:13.5px;font-weight:600;color:var(--dark)\">El Paso, TX<\/span><div style=\"width:140px;background:#e0e0d8;border-radius:3px;height:7px;overflow:hidden\"><div style=\"width:73.4%;background:#1b4332;height:7px;border-radius:3px\"><\/div><\/div><span style=\"font-size:14px;font-weight:800;color:#0d2818;width:44px;text-align:right\">37.9%<\/span><\/div>       <div style=\"display:flex;align-items:center;gap:12px;padding:8px 14px;background:#fafaf5;border-radius:8px;border:1px solid #e8e8e0\"><span style=\"font-size:16px;font-weight:800;color:#2d6a4f;width:22px;text-align:right;font-family:'Courier New',monospace\">5<\/span><span style=\"flex:1;font-size:13.5px;font-weight:600;color:var(--dark)\">Spartanburg, SC<\/span><div style=\"width:140px;background:#e0e0d8;border-radius:3px;height:7px;overflow:hidden\"><div style=\"width:73.1%;background:#52b788;height:7px;border-radius:3px\"><\/div><\/div><span style=\"font-size:14px;font-weight:800;color:#2d6a4f;width:44px;text-align:right\">37.7%<\/span><\/div>       <div style=\"display:flex;align-items:center;gap:12px;padding:8px 14px;background:#fafaf5;border-radius:8px;border:1px solid #e8e8e0\"><span style=\"font-size:16px;font-weight:800;color:#2d6a4f;width:22px;text-align:right;font-family:'Courier New',monospace\">6<\/span><span style=\"flex:1;font-size:13.5px;font-weight:600;color:var(--dark)\">Colorado Springs, CO<\/span><div style=\"width:140px;background:#e0e0d8;border-radius:3px;height:7px;overflow:hidden\"><div style=\"width:73.1%;background:#52b788;height:7px;border-radius:3px\"><\/div><\/div><span style=\"font-size:14px;font-weight:800;color:#2d6a4f;width:44px;text-align:right\">37.7%<\/span><\/div>       <div style=\"display:flex;align-items:center;gap:12px;padding:8px 14px;background:#f0fdf4;border-radius:8px;border:1px solid #bbf7d0\"><span style=\"font-size:16px;font-weight:800;color:#0d2818;width:22px;text-align:right;font-family:'Courier New',monospace\">7<\/span><span style=\"flex:1;font-size:13.5px;font-weight:600;color:var(--dark)\">Tyler, TX<\/span><div style=\"width:140px;background:#e0e0d8;border-radius:3px;height:7px;overflow:hidden\"><div style=\"width:72.1%;background:#1b4332;height:7px;border-radius:3px\"><\/div><\/div><span style=\"font-size:14px;font-weight:800;color:#0d2818;width:44px;text-align:right\">37.2%<\/span><\/div>       <div style=\"display:flex;align-items:center;gap:12px;padding:8px 14px;background:#fafaf5;border-radius:8px;border:1px solid #e8e8e0\"><span style=\"font-size:16px;font-weight:800;color:#2d6a4f;width:22px;text-align:right;font-family:'Courier New',monospace\">8<\/span><span style=\"flex:1;font-size:13.5px;font-weight:600;color:var(--dark)\">Seattle, WA<\/span><div style=\"width:140px;background:#e0e0d8;border-radius:3px;height:7px;overflow:hidden\"><div style=\"width:70.3%;background:#52b788;height:7px;border-radius:3px\"><\/div><\/div><span style=\"font-size:14px;font-weight:800;color:#2d6a4f;width:44px;text-align:right\">36.3%<\/span><\/div>       <div style=\"display:flex;align-items:center;gap:12px;padding:8px 14px;background:#f0fdf4;border-radius:8px;border:1px solid #bbf7d0\"><span style=\"font-size:16px;font-weight:800;color:#0d2818;width:22px;text-align:right;font-family:'Courier New',monospace\">9<\/span><span style=\"flex:1;font-size:13.5px;font-weight:600;color:var(--dark)\">Abilene, TX<\/span><div style=\"width:140px;background:#e0e0d8;border-radius:3px;height:7px;overflow:hidden\"><div style=\"width:68.8%;background:#1b4332;height:7px;border-radius:3px\"><\/div><\/div><span style=\"font-size:14px;font-weight:800;color:#0d2818;width:44px;text-align:right\">35.5%<\/span><\/div>       <div style=\"display:flex;align-items:center;gap:12px;padding:8px 14px;background:#f0fdf4;border-radius:8px;border:1px solid #bbf7d0\"><span style=\"font-size:16px;font-weight:800;color:#0d2818;width:22px;text-align:right;font-family:'Courier New',monospace\">10<\/span><span style=\"flex:1;font-size:13.5px;font-weight:600;color:var(--dark)\">Lubbock, TX<\/span><div style=\"width:140px;background:#e0e0d8;border-radius:3px;height:7px;overflow:hidden\"><div style=\"width:68.6%;background:#1b4332;height:7px;border-radius:3px\"><\/div><\/div><span style=\"font-size:14px;font-weight:800;color:#0d2818;width:44px;text-align:right\">35.4%<\/span><\/div>     <\/div>   <\/div>   <div style=\"border-left:4px solid #0077b6;padding:8px 18px;margin:28px 0 4px;background:linear-gradient(90deg,rgba(239,246,255,.6),transparent);border-radius:0 8px 8px 0\">     <p style=\"font-size:11px;letter-spacing:3px;text-transform:uppercase;color:#0077b6;font-family:\u2019Courier New\u2019,monospace;margin-bottom:2px\">Part II<\/p>     <h3 style=\"font-size:22px;color:#005f73;font-weight:700;margin:0\">How Much Do They Tip \u2014 and What Does It Mean for a Pro\u2019s Paycheck?<\/h3>   <\/div>   <div class=\"grid2\" style=\"margin-top:16px\">     <div class=\"chart-box\">       <h3>\ud83d\udcb8 Tip Rate: Which Big City Actually Tips?<\/h3>       <p class=\"note\">% of mowing jobs that got a tip, among the 20 largest markets. Not small towns \u2014 these are major metros doing thousands of jobs each. <strong>Knoxville<\/strong> leads at 32.2%; <strong>Orlando<\/strong> is dead last at 17.6%. <strong>Major-market avg: 24.8%<\/strong>.<\/p>       <canvas id=\"tipRateMajorChart\" height=\"420\"><\/canvas>     <\/div>     <div class=\"chart-box\">       <h3>\ud83d\udcb0 When They DO Tip \u2014 How Big Is the Check?<\/h3>       <p class=\"note\">Avg tip dollar amount, only counting jobs that received a tip. <strong>Chattanooga<\/strong> leads at $11.68; <strong>Houston<\/strong> comes in lowest at $7.92 \u2014 a nearly $4 gap between the top and bottom markets.<\/p>       <canvas id=\"tipAmtMajorChart\" height=\"420\"><\/canvas>     <\/div>   <\/div>   <div id=\"tip-pct-section\" class=\"chart-box\" style=\"margin-top:8px;padding:20px 28px\">     <h3>\ud83d\udcca How Generous Are Tips, Relative to the Total Bill?<\/h3>     <p class=\"note\">When customers tip, how much are they actually leaving? Measured as a share of the total job cost, <strong>San Antonio<\/strong> customers tip the highest \u2014 19.4% of the bill on average. <strong>Lakeland<\/strong> tips the smallest share at 16.4%. The <strong>national average is 17.9%<\/strong>, shown here across 20 major markets.<\/p>     <canvas id=\"tipPctChart\" height=\"150\"><\/canvas>   <\/div>    <div class=\"chart-box\" style=\"margin-top:16px\">     <h3>Tip Rate vs. Avg Tip Amount \u2014 Major Markets, 2025<\/h3>     <p class=\"note\">Each dot is a city. X-axis: tip rate (% of mows tipped). Y-axis: avg tip amount when tipped. The quadrants reveal why tip rate alone doesn\u2019t predict earnings. <strong>Hover over any dot for full stats.<\/strong><\/p>     <div id=\"scatterChart\"><\/div>   <\/div>    <div class=\"chart-box\" style=\"margin-top:8px;padding:20px 28px\">     <h3 style=\"font-size:18px\">\ud83c\udfc6 The Number That Actually Matters: Effective Tip Per Mow<\/h3>     <p class=\"note\">Tip rate \u00d7 avg tip amount, spread across <em>all<\/em> mows \u2014 tipped or not. This is the tip amount pros pocket, on average, per mow. Chattanooga ($3.47) earns <strong>more than double<\/strong> what Orlando pros make ($1.45). That $2.02\/mow gap adds up: at 6 mows\/day over a 35-week season, it's worth over $2,100 in additional take-home pay.<\/p>     <canvas id=\"effTipMajorChart\" height=\"110\"><\/canvas>   <\/div>   <div style=\"background:linear-gradient(135deg,#0d2818,#1b4332);border-radius:var(--r);padding:28px 32px;margin:28px 0 16px;color:#fff\">     <h4 style=\"color:#ffffff;font-size:24px;font-weight:800;margin-bottom:20px;letter-spacing:-.3px\">Tipping Myths \u2014 Busted<\/h4>     <div style=\"display:grid;grid-template-columns:1fr 1fr;gap:14px\">       <div style=\"background:rgba(255,255,255,.07);border-radius:10px;padding:18px\">         <p style=\"font-size:13px;font-weight:700;text-transform:uppercase;letter-spacing:2px;color:#ffffff;margin-bottom:6px;font-family:'Courier New',monospace\">Myth #1<\/p>         <p style=\"font-weight:700;font-size:15px;margin-bottom:8px;color:#fff\">\u201cPricier markets tip more\u201d<\/p>         <p style=\"font-size:13px;color:rgba(255,255,255,.72);line-height:1.65\"><strong>Orlando<\/strong> charges more per sq ft than <strong>Charlotte<\/strong> \u2014 but tips at a smaller rate (17.6% vs. 27%).<\/p>       <\/div>       <div style=\"background:rgba(255,255,255,.07);border-radius:10px;padding:18px\">         <p style=\"font-size:13px;font-weight:700;text-transform:uppercase;letter-spacing:2px;color:#ffffff;margin-bottom:6px;font-family:'Courier New',monospace\">Myth #2<\/p>         <p style=\"font-weight:700;font-size:15px;margin-bottom:8px;color:#fff\">\u201cBig cities tip the most\u201d<\/p>         <p style=\"font-size:13px;color:rgba(255,255,255,.72);line-height:1.65\"><strong>New York<\/strong>, <strong>LA<\/strong>, and <strong>Chicago<\/strong> all hover near the national average. It\u2019s mid-size <strong>Texas<\/strong> cities and <strong>Spartanburg, SC<\/strong> that dominate the top 10.<\/p>       <\/div>       <div style=\"background:rgba(255,255,255,.07);border-radius:10px;padding:18px\">         <p style=\"font-size:13px;font-weight:700;text-transform:uppercase;letter-spacing:2px;color:#ffffff;margin-bottom:6px;font-family:'Courier New',monospace\">Myth #3<\/p>         <p style=\"font-weight:700;font-size:15px;margin-bottom:8px;color:#fff\">\u201cWarm weather = generous tips\u201d<\/p>         <p style=\"font-size:13px;color:rgba(255,255,255,.72);line-height:1.65\"><strong>Seattle<\/strong> (36.3%) and <strong>Colorado Springs<\/strong> (37.7%) outperform every <strong>Florida<\/strong> city. Tipping culture is regional habit, not climate.<\/p>       <\/div>       <div style=\"background:rgba(255,255,255,.07);border-radius:10px;padding:18px\">         <p style=\"font-size:13px;font-weight:700;text-transform:uppercase;letter-spacing:2px;color:#ffffff;margin-bottom:6px;font-family:'Courier New',monospace\">Myth #4<\/p>         <p style=\"font-weight:700;font-size:15px;margin-bottom:8px;color:#fff\">\u201cHigh tip rate = high tip earnings\u201d<\/p>         <p style=\"font-size:13px;color:rgba(255,255,255,.72);line-height:1.65\">Rate and amount are independent. A city with a 35% rate and a $9 avg tip earns less per mow than one with 30% and $11. Effective tip per mow is the number that matters.<\/p>       <\/div>     <\/div>   <\/div>   <div class=\"chart-box\" style=\"margin-top:4px\">     <h3>Tipping Rate by State \u2014 2025<\/h3>     <p class=\"note\">% of completed mowing jobs that received a tip, by state. States with fewer than 290 mows excluded. <strong>National average: ~27%.<\/strong><\/p>     <div id=\"tipStateMap\" style=\"max-width:900px;margin:16px auto 8px\"><\/div>     <div class=\"map-legend\" style=\"max-width:900px;margin:0 auto\">       <span><span class=\"ld\" style=\"background:#d8f3dc\"><\/span>Under 25%<\/span>       <span><span class=\"ld\" style=\"background:#52b788\"><\/span>25\u201330%<\/span>       <span><span class=\"ld\" style=\"background:#2d6a4f\"><\/span>30\u201335%<\/span>       <span><span class=\"ld\" style=\"background:#1b4332\"><\/span>35\u201345%<\/span>       <span><span class=\"ld\" style=\"background:#0a2e1a\"><\/span>45%+<\/span>     <\/div>   <\/div>    <div class=\"callout c-green\" style=\"margin-top:24px\">     <div class=\"callout-icon\">\ud83c\udf6a<\/div>     <div>       <h4>Pros Weigh In: Tips, Reviews, and Homemade Cookies<\/h4>       <p style=\"margin-bottom:12px\">\u201cI'm usually surprised by the tips, positive comments, and 5-star ratings,\u201d says LawnStarter pro David Beach (Westside Mowing) in San Antonio. \u201cAs long as you take pride in your work and are professional, I think the accolades, whether they are monetary or documented praise, come on their own without having to make a concentrated effort.\u201d<\/p>       <p>Beyond cash tips, our pros share that they appreciate courtesy gifts like water and snacks the most. Another San Antonio LawnStarter pro, Gabriel Sosa (At Your Service), says, \u201cI did receive home-baked Christmas cookies once.\u201d For many pros, these gestures are a bonus \u2014 not an expectation. \u201cI try to treat all my customers exactly the same, tip or no tip,\u201d Sosa shares.<\/p>     <\/div>   <\/div> <\/section> <\/div>  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 TIPPING YoY \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 --> <section id=\"tipping-yoy\" class=\"section fade\">   <p class=\"section-tag\">Year-Over-Year &middot; 2024 vs. 2025 &middot; 2K+ Cities<\/p>   <h2>More Americans Tipped Their Lawn Pros in 2025 Than Ever Before<\/h2>   <p class=\"lead\">Something shifted in 2025 &mdash; across more than 2,000 cities, the national tip rate jumped from <strong>19.1%<\/strong> to <strong>26.7%<\/strong> in a single year, with 4 in 5 markets posting gains. What&rsquo;s surprising is that the average tip dollar barely budged. This wasn&rsquo;t existing tippers spending more &mdash; it was an entirely new wave of people <em style=\"color:#2d6a4f\">starting<\/em> to tip their lawn pros for the first time.<\/p>    <div class=\"cards\" style=\"margin-bottom:40px\">     <div class=\"card\" style=\"background:#edf7f2;border-color:#52b788\">       <div class=\"card-label\" style=\"color:#2d6a4f\">Markets Where Rate Rose<\/div>       <div class=\"card-num\" style=\"color:#1b4332;font-size:clamp(30px,4vw,42px)\">80<span style=\"font-size:60%;font-weight:600\">%<\/span><\/div>       <div class=\"card-sub\">1,700+ out of 2,200+ cities analyzed<\/div>     <\/div>     <div class=\"card\" style=\"background:#edf7f2;border-color:var(--g3)\">       <div class=\"card-label\" style=\"color:var(--g3)\">More Customers Tipping<\/div>       <div class=\"card-num\" style=\"color:#1b4332;font-size:clamp(30px,4vw,42px)\">+40<span style=\"font-size:60%;font-weight:600\">%<\/span><\/div>       <div class=\"card-sub\">19.1% &rarr; 26.7% of all mows &mdash; biggest single-year jump on record<\/div>     <\/div>     <div class=\"card\" style=\"background:#fdf8ed;border-color:#d97706\">       <div class=\"card-label\" style=\"color:#b45309\">Avg Tip When Given<\/div>       <div class=\"card-num\" style=\"color:#92400e;font-size:clamp(30px,4vw,42px)\">$9.55<\/div>       <div class=\"card-sub\">Up from $9.42 in 2024 &middot; +$0.14<\/div>     <\/div>     <div class=\"card\" style=\"background:#eff8ff;border-color:#0284c7\">       <div class=\"card-label\" style=\"color:#0369a1\">Tip as % of Job<\/div>       <div class=\"card-num\" style=\"color:#0c4a6e;font-size:clamp(30px,4vw,42px)\">17.9<span style=\"font-size:60%;font-weight:600\">%<\/span><\/div>       <div class=\"card-sub\">Down from 18.6% &middot; new tippers tip conservatively<\/div>     <\/div>   <\/div>    <div class=\"chart-box\" style=\"margin-bottom:40px\">     <h3>How Every State Moved: Tipping Trends 2024 &rarr; 2025<\/h3>     <p class=\"note\">Three things can change in tipping: <strong>how often<\/strong> customers tip (the tip rate &mdash; share of jobs that got a tip), <strong>how much<\/strong> they tip (the dollar amount), and <strong>what share of the total bill<\/strong> they tip. Map labels show relative change in tip rate. Color reflects how tip rate and tip dollar shifted together from 2024 to 2025. Hover any state to see all three metrics.<\/p>     <div id=\"tipYoYMap\" style=\"max-width:900px;margin:16px auto 8px\"><\/div>     <div class=\"map-legend\" style=\"max-width:900px;margin:0 auto\">       <span><span class=\"ld\" style=\"background:#1b4332\"><\/span>More tipping &amp; bigger tip amounts (both jumped strongly)<\/span>       <span><span class=\"ld\" style=\"background:#2d6a4f\"><\/span>More tipping &amp; bigger tip amounts<\/span>       <span><span class=\"ld\" style=\"background:#52b788\"><\/span>More tipping, tip amounts about the same<\/span>       <span><span class=\"ld\" style=\"background:#f4a261\"><\/span>More tipping, but tip amounts fell<\/span>       <span><span class=\"ld\" style=\"background:#e63946\"><\/span>Tipping rate fell vs. 2024<\/span>     <\/div>   <\/div>    <div style=\"padding-top:36px;border-top:2px solid #d8ede1\">     <p class=\"section-tag\">Top 20 Major Markets<\/p>     <h3 style=\"font-size:clamp(20px,3vw,28px);margin:0 0 8px\">Not One Major Market Missed the Wave<\/h3>     <p style=\"color:var(--mid);max-width:820px;margin:0 0 28px;font-size:15px;line-height:1.6\">Among the 20 largest markets, every single city saw its tip rate rise. <strong>Nashville<\/strong> and <strong>St.&nbsp;Louis<\/strong> both gained more than 10 percentage points. Even <strong>Detroit<\/strong>, the most reluctant market, climbed nearly 5 points.<\/p>      <div class=\"chart-box\" style=\"margin-bottom:16px\">       <h3>Where Did Tipping Grow the Most in 2025?<\/h3>       <p class=\"note\">How much more often did customers tip in 2025 vs. 2024? Each bar shows the gain in tip rate from biggest to smallest. National average: <strong style=\"color:#2d6a4f\">+7.6 percentage points<\/strong>. <span style=\"font-weight:600;color:#2d6a4f\">Darker green = bigger gain.<\/span><\/p>       <canvas id=\"yoyRateChart\" height=\"220\"><\/canvas>     <\/div>      <div class=\"grid2\">       <div class=\"chart-box\">         <h3>Did the Tip Amount Go Up or Down? Average Tip in Dollars, 2024 vs. 2025<\/h3>         <p class=\"note\">Change in average tip dollar amount per tipped job. Mixed results &mdash; Chicago saw +$0.47 more per tip; Detroit dropped &minus;$0.54. National average change: <strong style=\"color:#2d6a4f\">+$0.14<\/strong>.<\/p>         <canvas id=\"yoyAmtChart\" height=\"420\"><\/canvas>       <\/div>       <div class=\"chart-box\">         <h3>Tips as a Share of the Bill &mdash; Did They Go Up or Down?<\/h3>         <p class=\"note\">Of the total job price, what percentage do customers tip? <span style=\"color:#c8960a\">Yellow = 2024<\/span>, <span style=\"color:#2d6a4f\">green = 2025<\/span>. Every city slipped slightly &mdash; because new tippers tend to start with smaller tips relative to the bill. Nationally, the share fell from <strong style=\"color:#b45309\">18.6%<\/strong> to <strong style=\"color:#2d6a4f\">17.9%<\/strong> of the total job price.<\/p>         <canvas id=\"yoyPctChart\" height=\"420\"><\/canvas>       <\/div>     <\/div>      <div class=\"grid2\" style=\"margin-top:0\">       <div class=\"callout c-green\" style=\"margin:0\">         <div class=\"callout-icon\">&#x1F680;<\/div>         <div>           <h4>What sparked the jump?<\/h4>           <p>As tipping for outdoor services becomes culturally normalized &mdash; mirroring the path restaurants took decades ago &mdash; frequency rises first. Dollar amounts typically follow in subsequent years once the behavior is fully established.<\/p>         <\/div>       <\/div>       <div class=\"callout c-amber\" style=\"margin:0\">         <div class=\"callout-icon\">&#x1F4BC;<\/div>         <div>           <h4>What it meant for a Nashville pro&rsquo;s paycheck<\/h4>           <p>Nashville&rsquo;s tip rate jumped from 19.5% to 30.3%, lifting the effective tip per mow from $1.95 to $3.05. At 6 mows\/day over a 35-week season, that&rsquo;s over <strong>$1,150 more in take-home tip earnings<\/strong> in 2025 than in 2024 &mdash; from rate improvement alone, without any single customer tipping a dollar more.<\/p>         <\/div>       <\/div>     <\/div>   <\/div>  <\/section>   <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 LOOKING AHEAD \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 --> <section id=\"looking-ahead\" class=\"section fade\">   <p class=\"section-tag\">Looking Ahead<\/p>   <h2>Looking Ahead: 2026 Mowing Season<\/h2>   <p class=\"lead\">All systems are green (or greening up) across the U.S. Lawn care pros have been mowing yards in Texas for weeks, Florida is starting slowly because of the ongoing drought, and lawn care pros are struggling with gas prices, which fuel their trucks and power much of their lawn care equipment. We're tracking mows, frequencies, prices, and tips for a similar by-the-numbers LawnStarter industry report next year. Will July 3 be the peak mowing day for 2026? Stay tuned.<\/p> <\/section>  <!-- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 BY THE NUMBERS \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 --> <div class=\"band band-slate\"> <section class=\"section fade\">   <p class=\"section-tag\">The Full Picture<\/p>   <h2>By the Numbers: 2025 American Lawn Care<\/h2>   <p class=\"lead\">Every season. Every schedule. Here's what 2M+ mowing jobs reveal about how America cares for its lawns.<\/p>    <div class=\"btn-grid\">     <a href=\"#annual-cost\" style=\"text-decoration:none;color:inherit;display:block\" class=\"btn-stat cat-price\"><div class=\"btn-illus\"><span class=\"bi-m\">\ud83c\udf3f<\/span><span class=\"bi-a\">\ud83d\udcb0<\/span><\/div><div class=\"btn-text\"><div class=\"btn-num\">$407\/yr<\/div><div class=\"btn-label\">avg annual lawn care spending<\/div><\/div><\/a>     <a href=\"#state-pricing\" style=\"text-decoration:none;color:inherit;display:block\" class=\"btn-stat cat-price\"><div class=\"btn-illus\"><span class=\"bi-m\">\ud83d\udcc8<\/span><span class=\"bi-a\">\ud83d\udcb5<\/span><\/div><div class=\"btn-text\"><div class=\"btn-num\">+6.6%<\/div><div class=\"btn-label\">avg price increase vs. 2024<\/div><\/div><\/a>     <a href=\"#stateP1kChangeMap\" style=\"text-decoration:none;color:inherit;display:block\" class=\"btn-stat cat-price\"><div class=\"btn-illus\"><span class=\"bi-m\">\ud83d\udcd0<\/span><span class=\"bi-a\">\u2b06\ufe0f<\/span><\/div><div class=\"btn-text\"><div class=\"btn-num\">+4.8%<\/div><div class=\"btn-label\">price per 1,000 sq\u00a0ft up YoY<\/div><\/div><\/a>     <a href=\"#seasonal\" style=\"text-decoration:none;color:inherit;display:block\" class=\"btn-stat cat-price\"><div class=\"btn-illus\"><span class=\"bi-m\">\u2600\ufe0f<\/span><span class=\"bi-a\">\u2744\ufe0f<\/span><\/div><div class=\"btn-text\"><div class=\"btn-num\">+10.9%<\/div><div class=\"btn-label\">peak-season price premium \u2014 Aug vs. Jan<\/div><\/div><\/a>     <a href=\"#tipping\" style=\"text-decoration:none;color:inherit;display:block\" class=\"btn-stat cat-tip\"><div class=\"btn-illus\"><span class=\"bi-m\">\ud83d\udcb0<\/span><span class=\"bi-a\">\ud83d\ude4c<\/span><\/div><div class=\"btn-text\"><div class=\"btn-num\">$9.55<\/div><div class=\"btn-label\">avg tip when a tip is given<\/div><\/div><\/a>     <a href=\"#tip-pct-section\" style=\"text-decoration:none;color:inherit;display:block\" class=\"btn-stat cat-tip\"><div class=\"btn-illus\"><span class=\"bi-m\">\ud83d\udcaf<\/span><span class=\"bi-a\">\ud83d\udcb5<\/span><\/div><div class=\"btn-text\"><div class=\"btn-num\">17.9%<\/div><div class=\"btn-label\">avg tip as % of the job price<\/div><\/div><\/a>     <a href=\"#weather\" style=\"text-decoration:none;color:inherit;display:block\" class=\"btn-stat cat-weather\"><div class=\"btn-illus\"><span class=\"bi-m\">\ud83c\udf27\ufe0f<\/span><span class=\"bi-a\">\ud83c\udf43<\/span><\/div><div class=\"btn-text\"><div class=\"btn-num\">5.7%<\/div><div class=\"btn-label\">of mows disrupted by weather<\/div><\/div><\/a>     <a href=\"#scheduling\" style=\"text-decoration:none;color:inherit;display:block\" class=\"btn-stat cat-schedule\"><div class=\"btn-illus\"><span class=\"bi-m\">\ud83d\udcc5<\/span><span class=\"bi-a\">\u2b50<\/span><\/div><div class=\"btn-text\"><div class=\"btn-num\">Thursday<\/div><div class=\"btn-label\">most popular mowing day<\/div><\/div><\/a>     <a href=\"#scheduling\" style=\"text-decoration:none;color:inherit;display:block\" class=\"btn-stat cat-schedule\"><div class=\"btn-illus\"><span class=\"bi-m\">\ud83d\udcbc<\/span><span class=\"bi-a\">\u2705<\/span><\/div><div class=\"btn-text\"><div class=\"btn-num\">82.1%<\/div><div class=\"btn-label\">of all mows happen on weekdays<\/div><\/div><\/a>     <a href=\"#annual-cost\" style=\"text-decoration:none;color:inherit;display:block\" class=\"btn-stat cat-schedule\"><div class=\"btn-illus\"><span class=\"bi-m\">\ud83c\udfe1<\/span><span class=\"bi-a\">\ud83d\udd04<\/span><\/div><div class=\"btn-text\"><div class=\"btn-num\">7.6<\/div><div class=\"btn-label\">avg mows scheduled per property<\/div><\/div><\/a>     <a href=\"#seasonal\" style=\"text-decoration:none;color:inherit;display:block\" class=\"btn-stat cat-season\"><div class=\"btn-illus\"><span class=\"bi-m\">\ud83c\udf3b<\/span><span class=\"bi-a\">\u2600\ufe0f<\/span><\/div><div class=\"btn-text\"><div class=\"btn-num\">July<\/div><div class=\"btn-label\">peak mowing month nationally<\/div><\/div><\/a>     <a href=\"#weather\" style=\"text-decoration:none;color:inherit;display:block\" class=\"btn-stat cat-season\"><div class=\"btn-illus\"><span class=\"bi-m\">\u2744\ufe0f<\/span><span class=\"bi-a\">\ud83d\udeab<\/span><\/div><div class=\"btn-text\"><div class=\"btn-num\">December<\/div><div class=\"btn-label\">peak cancellation month<\/div><\/div><\/a>   <\/div>  <\/section> <\/div>  <section class=\"section fade\" style=\"background:#f7f7f2;padding:48px 24px\">   <div style=\"max-width:760px;margin:0 auto\">     <p class=\"section-tag\">Methodology<\/p>     <h2 style=\"font-size:22px;margin-bottom:16px\">How We Compiled This Report<\/h2>     <p style=\"font-size:15px;line-height:1.8;color:#444\">Data covers lawn mowing service transactions completed through LawnStarter across 2K+ U.S. cities in 2025. The full dataset includes 2M+ mowing jobs. Metrics include price per 1,000 sq ft, tip amount and frequency, weather disruption rate, and mows per property per year. All weighted averages are calculated by mow volume. State-level figures are computed from cities in the LawnStarter dataset, weighted by mow volume, and are representative of LawnStarter service areas. Annual cost estimates multiply average price by average mows per property for cities where both metrics are available. Weather disruption is defined as mowing jobs rescheduled or cancelled due to weather. Tip data reflects voluntary gratuities at time of payment.<\/p>   <\/div> <\/section> <footer>   <p>Based on data from markets where LawnStarter operates.<\/p> <\/footer>  <script>\n\/\/ \u2500\u2500 SCROLL OBSERVER \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst obs = new IntersectionObserver(els => els.forEach(e => { if(e.isIntersecting) e.target.classList.add('vis') }), {threshold:0.08});\ndocument.querySelectorAll('.fade').forEach(el => obs.observe(el));\n\n\/\/ (Map removed \u2014 section deleted)\n\n\/\/ \u2500\u2500 CHARTS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst G = id => document.getElementById(id).getContext('2d');\n\n\/\/ Monthly\nnew Chart(G('monthlyChart'),{type:'bar',data:{\n  labels:['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],\n  datasets:[{\n    data:[44554,48505,96219,188837,257484,271083,291198,277050,247418,210713,112635,63522],\n    backgroundColor:['#d8f3dc','#d8f3dc','#95d5b2','#52b788','#2d6a4f','#2d6a4f','#1b4332','#2d6a4f','#52b788','#95d5b2','#d8f3dc','#d8f3dc'],\n    borderRadius:6\n  }]\n},options:{plugins:{legend:{display:false}},scales:{y:{ticks:{callback:v=>v>=1000?Math.round(v\/1000)+'K':v},grid:{color:'#f0f0ea'}},x:{grid:{display:false}}}}});\n\n\/\/ Day of week\nnew Chart(G('dowChart'),{type:'bar',data:{\n  labels:['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],\n  datasets:[{\n    data:[7.16,15.23,16.52,16.79,16.88,16.66,10.75],\n    backgroundColor:['#d8f3dc','#52b788','#52b788','#2d6a4f','#1b4332','#2d6a4f','#95d5b2'],\n    borderRadius:6\n  }]\n},options:{plugins:{legend:{display:false}},scales:{y:{ticks:{callback:v=>v+'%'},grid:{color:'#f0f0ea'}},x:{grid:{display:false}}}}});\n\n\/\/ ZIP spread\nnew Chart(G('zipSpreadChart'),{type:'bar',data:{\n  labels:['Los Angeles, CA','Glendale, AZ','Euless, TX','Woodinville, WA','Denton, TX','Nashua, NH','Gilbert, AZ','Bridgeport, CT','Pittsburgh, PA','Cincinnati, OH','Davie, FL','Madison, WI','Phoenix, AZ','San Diego, CA','Atlanta, GA'],\n  datasets:[{\n    data:[38,37,33,30,29,29,28,28,28,27,27,27,27,26,26],\n    backgroundColor:(ctx)=>{const v=ctx.raw;return v>=35?'#e63946':v>=25?'#e76f51':v>=15?'#f4a261':'#52b788'},\n    borderRadius:4\n  }]\n},options:{indexAxis:'y',plugins:{legend:{display:false},tooltip:{callbacks:{label:ctx=>' $'+ctx.raw+' spread'}}},scales:{x:{ticks:{callback:v=>'$'+v},grid:{color:'#f5f5f0'}},y:{grid:{display:false},ticks:{font:{size:12}}}}}});\n\n\/\/ \u2500\u2500 D3 GEOGRAPHIC STATE MAPS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst SN={AL:'Alabama',AK:'Alaska',AZ:'Arizona',AR:'Arkansas',CA:'California',CO:'Colorado',CT:'Connecticut',DC:'D.C.',DE:'Delaware',FL:'Florida',GA:'Georgia',HI:'Hawaii',IA:'Iowa',ID:'Idaho',IL:'Illinois',IN:'Indiana',KS:'Kansas',KY:'Kentucky',LA:'Louisiana',MA:'Massachusetts',MD:'Maryland',ME:'Maine',MI:'Michigan',MN:'Minnesota',MO:'Missouri',MS:'Mississippi',MT:'Montana',NC:'North Carolina',ND:'North Dakota',NE:'Nebraska',NH:'New Hampshire',NJ:'New Jersey',NM:'New Mexico',NV:'Nevada',NY:'New York',OH:'Ohio',OK:'Oklahoma',OR:'Oregon',PA:'Pennsylvania',RI:'Rhode Island',SC:'South Carolina',SD:'South Dakota',TN:'Tennessee',TX:'Texas',UT:'Utah',VA:'Virginia',VT:'Vermont',WA:'Washington',WI:'Wisconsin',WV:'West Virginia',WY:'Wyoming'};\nlet _tt=null;\nfunction _getTt(){if(!_tt){_tt=document.createElement('div');_tt.style.cssText='position:fixed;background:rgba(15,25,20,.92);color:#fff;padding:7px 14px;border-radius:8px;font-size:13px;pointer-events:none;opacity:0;transition:opacity .15s;z-index:9999;box-shadow:0 4px 16px rgba(0,0,0,.35)';document.body.appendChild(_tt);\n  \/\/ Mobile: tap-to-show fires mouseover but mouseout never fires until next tap, so the\n  \/\/ tooltip stays \"stuck\" on the page after scrolling away. Dismiss on scroll or any\n  \/\/ touch \u2014 on iOS, touchstart precedes the synthesized mouseover, so a tap on a new\n  \/\/ state still shows the new tooltip correctly.\n  const _hideTt=()=>{_tt.style.opacity='0';};\n  window.addEventListener('scroll',_hideTt,{passive:true,capture:true});\n  window.addEventListener('touchstart',_hideTt,{passive:true});\n}return _tt;}\nconst _fipsMap={'01':'AL','02':'AK','04':'AZ','05':'AR','06':'CA','08':'CO','09':'CT','10':'DE','11':'DC','12':'FL','13':'GA','15':'HI','16':'ID','17':'IL','18':'IN','19':'IA','20':'KS','21':'KY','22':'LA','23':'ME','24':'MD','25':'MA','26':'MI','27':'MN','28':'MS','29':'MO','30':'MT','31':'NE','32':'NV','33':'NH','34':'NJ','35':'NM','36':'NY','37':'NC','38':'ND','39':'OH','40':'OK','41':'OR','42':'PA','44':'RI','45':'SC','46':'SD','47':'TN','48':'TX','49':'UT','50':'VT','51':'VA','53':'WA','54':'WV','55':'WI','56':'WY'};\nlet _atlasPromise=null;\nfunction _getAtlas(){if(!_atlasPromise)_atlasPromise=fetch('https:\/\/cdn.jsdelivr.net\/npm\/us-atlas@3\/states-10m.json').then(r=>r.json());return _atlasPromise;}\nfunction buildSVGMap(containerId,data,colorFn,labelFn){\n  const el=document.getElementById(containerId);if(!el)return;\n  const W=960,H=600,ns='http:\/\/www.w3.org\/2000\/svg';\n  const svg=document.createElementNS(ns,'svg');\n  svg.setAttribute('viewBox','0 0 '+W+' '+H);\n  svg.setAttribute('style','width:100%;height:auto;display:block;border-radius:8px');\n  const bg=document.createElementNS(ns,'rect');\n  bg.setAttribute('width',W);bg.setAttribute('height',H);bg.setAttribute('fill','#eef2f0');bg.setAttribute('rx','8');svg.appendChild(bg);\n  const tt=_getTt();\n  _getAtlas().then(us=>{\n    const states=topojson.feature(us,us.objects.states);\n    const proj=d3.geoAlbersUsa().scale(1280).translate([W\/2,H\/2]);\n    const path=d3.geoPath().projection(proj);\n    const small=new Set(['CT','RI','DE','DC','NJ','MD','MA','VT','NH','ME']);\n    const smallC={};\n    states.features.forEach(f=>{\n      const fips=String(f.id).padStart(2,'0');\n      const abbr=_fipsMap[fips];if(!abbr)return;\n      const val=data[abbr];\n      const pd=path(f);if(!pd)return;\n      const pe=document.createElementNS(ns,'path');\n      pe.setAttribute('d',pd);\n      pe.setAttribute('fill',val!=null?colorFn(val):'#d8dbd6');\n      pe.setAttribute('stroke','#fff');pe.setAttribute('stroke-width','0.6');\n      pe.style.cursor='pointer';pe.style.transition='filter .12s';\n      pe.addEventListener('mouseover',()=>{pe.style.filter='brightness(1.12)';tt.style.opacity='1';tt.innerHTML='<strong>'+(SN[abbr]||abbr)+'<\/strong>: '+(val!=null?labelFn(val):'No data');});\n      pe.addEventListener('mousemove',e=>{tt.style.left=(e.clientX+14)+'px';tt.style.top=(e.clientY-36)+'px';});\n      pe.addEventListener('mouseout',()=>{pe.style.filter='';tt.style.opacity='0';});\n      svg.appendChild(pe);\n      const _cFix={MI:[673,176],FL:[770,508],WV:[758,274],HI:[272,545]};\n      const c=_cFix[abbr]||path.centroid(f);\n      if(c&&!isNaN(c[0])&&!isNaN(c[1])){\n        if(small.has(abbr)){\n          smallC[abbr]=c;\n        } else {\n          const tx=document.createElementNS(ns,'text');\n          tx.setAttribute('x',c[0]);tx.setAttribute('y',val!=null?c[1]-9:c[1]);\n          tx.setAttribute('text-anchor','middle');tx.setAttribute('dominant-baseline','middle');\n          tx.setAttribute('font-size','16');tx.setAttribute('font-family','\"Courier New\",monospace');\n          tx.setAttribute('font-weight','700');tx.setAttribute('fill',val!=null?'#fff':'#999');\n          tx.setAttribute('pointer-events','none');tx.textContent=abbr;svg.appendChild(tx);\n          if(val!=null){\n            const vx=document.createElementNS(ns,'text');\n            vx.setAttribute('x',c[0]);vx.setAttribute('y',c[1]+12);\n            vx.setAttribute('text-anchor','middle');vx.setAttribute('dominant-baseline','middle');\n            vx.setAttribute('font-size','13');vx.setAttribute('font-family','\"Courier New\",monospace');\n            vx.setAttribute('fill','rgba(255,255,255,0.95)');vx.setAttribute('pointer-events','none');\n            vx.textContent=labelFn(val);svg.appendChild(vx);\n          }\n        }\n      }\n    });\n    \/\/ Northeast small-states panel (bottom-right, Atlantic Ocean area)\n    const neList=['ME','NH','VT','MA','RI','CT','NJ','DE','MD','DC'];\n    const px=808,py=308,pw=152,ph=neList.length*24+28;\n    const pb=document.createElementNS(ns,'rect');\n    pb.setAttribute('x',px);pb.setAttribute('y',py);pb.setAttribute('width',pw);pb.setAttribute('height',ph);\n    pb.setAttribute('fill','rgba(255,255,255,0.94)');pb.setAttribute('rx','5');pb.setAttribute('stroke','#bbb');pb.setAttribute('stroke-width','0.7');\n    svg.appendChild(pb);\n    const ptx=document.createElementNS(ns,'text');\n    ptx.setAttribute('x',px+pw\/2);ptx.setAttribute('y',py+17);\n    ptx.setAttribute('text-anchor','middle');ptx.setAttribute('font-size','13');\n    ptx.setAttribute('font-family','\"Courier New\",monospace');ptx.setAttribute('font-weight','700');ptx.setAttribute('fill','#444');\n    ptx.textContent='Northeast';svg.appendChild(ptx);\n    neList.forEach((abbr,i)=>{\n      const val=data[abbr];\n      const ry=py+31+i*24;\n      const sw=document.createElementNS(ns,'rect');\n      sw.setAttribute('x',px+7);sw.setAttribute('y',ry-7);sw.setAttribute('width','13');sw.setAttribute('height','13');\n      sw.setAttribute('fill',val!=null?colorFn(val):'#d8dbd6');sw.setAttribute('rx','2');svg.appendChild(sw);\n      const at=document.createElementNS(ns,'text');\n      at.setAttribute('x',px+26);at.setAttribute('y',ry+2);\n      at.setAttribute('font-size','13');at.setAttribute('font-family','\"Courier New\",monospace');\n      at.setAttribute('font-weight','700');at.setAttribute('fill','#111');\n      at.textContent=abbr;svg.appendChild(at);\n      if(val!=null){\n        const vt=document.createElementNS(ns,'text');\n        vt.setAttribute('x',px+pw-7);vt.setAttribute('y',ry+2);\n        vt.setAttribute('text-anchor','end');vt.setAttribute('font-size','13');\n        vt.setAttribute('font-family','\"Courier New\",monospace');vt.setAttribute('fill','#333');\n        vt.textContent=labelFn(val);svg.appendChild(vt);\n      }\n      if(smallC[abbr]){\n        const dot=document.createElementNS(ns,'circle');\n        dot.setAttribute('cx',smallC[abbr][0]);dot.setAttribute('cy',smallC[abbr][1]);\n        dot.setAttribute('r','3');dot.setAttribute('fill',val!=null?colorFn(val):'#d8dbd6');\n        dot.setAttribute('stroke','#fff');dot.setAttribute('stroke-width','1');\n        dot.setAttribute('pointer-events','none');svg.appendChild(dot);\n      }\n    });\n    el.appendChild(svg);\n  });\n}\n\n\/\/ State price map data (verified from Redshift; 500+ mow threshold for most states, lower-volume markets included where available)\nbuildSVGMap('statePriceMap',\n  {AK:62.83,AL:58.1,AR:55.85,AZ:45.08,CA:45.73,CO:54.79,CT:64.62,DC:48.53,DE:58.38,FL:51.12,GA:56.49,HI:57.43,IA:56.03,ID:54.45,IL:56.76,IN:56.88,KS:55.08,KY:56.06,LA:51.15,MA:62.84,MD:55.23,ME:76.27,MI:56.14,MN:59.42,MO:54.95,MS:60.16,NC:57.71,ND:64.4,NE:55.34,NH:64.0,NJ:60.72,NM:45.3,NV:50.32,NY:58.34,OH:55.21,OK:52.39,OR:52.61,PA:56.51,RI:56.07,SC:58.52,SD:62.31,TN:60.22,TX:50.33,UT:58.53,VA:58.87,VT:78.15,WA:56.42,WI:58.0,WV:61.28,WY:60.56},\n  v=>v<50?'#2d6a4f':v<54?'#52b788':v<58?'#f4a261':v<62?'#e76f51':'#e63946',\n  v=>'$'+v.toFixed(2)\n);\n\n\/\/ Price per 1,000 sq ft YoY change map (2024\u21922025)\n\/\/ Sources: Google Sheet city-level data for most states; Redshift for small\/sparse states (DC,ME,ND,NH,NM,NV,VT,WY).\n\/\/ WV uses Sheet data (+7.6%; Redshift shows small decrease inconsistent with inflation trends).\n\/\/ AK excluded: only 19 qualifying mows in 2024 \u2014 insufficient for reliable p1k calculation.\n\/\/ HI excluded: single Ewa Beach city; yard-size composition shift drives misleading +36% artifact.\n\/\/ MT excluded: no qualifying mow data in either year.\n\/\/ SD excluded: Sioux Falls only (\u226525 mows\/yr); yard-size composition shift produces misleading outlier.\n\/\/ WY excluded: sparse\/Redshift-sourced state; low job volume makes YoY % highly volatile.\nbuildSVGMap('stateP1kChangeMap',\n  {AL:2.8,AR:9.0,AZ:0.9,CA:2.5,CO:7.9,CT:4.5,DC:2.8,DE:1.6,FL:6.2,GA:3.8,IA:1.3,ID:0.7,IL:6.7,IN:5.5,KS:2.9,KY:2.4,LA:5.1,MA:4.4,MD:6.1,ME:4.5,MI:3.7,MN:5.9,MO:8.1,MS:4.7,NC:4.8,ND:9.1,NE:2.2,NH:4.3,NJ:10.5,NM:2.3,NV:5.3,NY:9.3,OH:3.4,OK:5.7,OR:9.5,PA:5.6,TN:5.3,TX:6.2,UT:4.3,VA:5.6,VT:1.0,WA:3.8,WI:3.8,WV:7.6},\n  v=>v>=9?'#e63946':v>=6?'#f4a261':v>=3?'#52b788':'#a8dadc',\n  v=>'+'+v.toFixed(1)+'%'\n);\n\n\/\/ Season length map data (months with active mowing)\nbuildSVGMap('seasonMap',\n  {AK:8,AL:10,AR:9,AZ:10,CA:10,CO:7,CT:7,DC:10,DE:8,FL:11,GA:10,HI:12,IA:7,ID:7,IL:7,IN:8,KS:8,KY:7,LA:10,MA:7,MD:8,ME:8,MI:7,MN:6,MO:8,MS:9,MT:6,NC:9,ND:7,NE:8,NH:6,NJ:7,NM:9,NV:8,NY:7,OH:8,OK:8,OR:9,PA:7,RI:7,SC:9,SD:8,TN:9,TX:11,UT:7,VA:9,VT:6,WA:9,WI:7,WV:7,WY:6},\n  v=>v<=6?'#d8f3dc':v<=7?'#95d5b2':v<=8?'#52b788':v<=9?'#2d6a4f':v<=10?'#1b4332':'#0a2e1a',\n  v=>v>=11?'~Year':v>=10?'Extended':v>=9?'Long':v>=8?'Mid':v>=7?'Short':'Brief'\n);\n\n\/\/ Weather disruption map data (% of jobs disrupted by weather)\nbuildSVGMap('weatherMap',\n  {AK:2.04,AL:9.49,AR:8.95,AZ:2.85,CA:2.17,CO:5.00,CT:10.89,DC:9.15,DE:4.54,FL:6.16,GA:8.13,HI:3.49,IA:7.73,ID:1.54,IL:5.63,IN:5.69,KS:5.16,KY:6.56,LA:6.71,MA:4.87,MD:8.92,ME:4.27,MI:5.73,MN:5.98,MO:7.12,MS:6.49,MT:1.10,NC:7.58,NE:7.49,NH:6.38,NJ:7.20,NM:0.65,NV:4.68,NY:8.45,OH:7.43,OK:7.73,OR:2.56,PA:8.16,RI:8.51,SC:8.20,SD:4.02,TN:8.53,TX:5.70,UT:8.68,VA:6.73,VT:1.65,WA:2.64,WI:5.89,WV:4.20,WY:3.09},\n  v=>v<3?'#d8f3dc':v<5?'#52b788':v<7?'#f4a261':v<9?'#e76f51':'#e63946',\n  v=>v<3?'Rare':v<5?'Occas.':v<7?'Freq.':v<9?'Often':'High'\n);\n\n\/\/ State tip rate map (states with 500+ mows; SD\/VT\/HI included where previously present or near threshold)\nbuildSVGMap('tipStateMap',\n  {AL:31.1,AR:29.78,AZ:31.1,CA:27.46,CO:33.22,CT:28.12,DC:20.94,DE:28.39,FL:22.81,GA:24.54,HI:32.35,IA:33.31,ID:32.25,IL:24.7,IN:28.46,KS:31.78,KY:30.76,LA:26.02,MA:29.95,MD:26.2,ME:43.82,MI:27.5,MN:32.47,MO:29.57,MS:27.58,NC:27.98,ND:40.79,NE:34.14,NH:39.47,NJ:25.64,NM:59.19,NV:32.06,NY:27.0,OH:28.66,OK:30.65,OR:32.75,PA:30.25,RI:32.85,SC:28.27,SD:32.56,TN:30.18,TX:25.12,UT:30.44,VA:28.54,VT:35.52,WA:33.11,WI:33.06,WV:34.73},\n  v=>v<25?'#d8f3dc':v<30?'#52b788':v<35?'#2d6a4f':v<45?'#1b4332':'#0a2e1a',\n  v=>v.toFixed(1)+'%'\n);\n\n\/\/ Market price (price per 1,000 sqft)\nnew Chart(G('marketPriceChart'),{type:'bar',data:{\n  labels:['Knoxville TN','Raleigh NC','Chattanooga TN','Lakeland FL','Richmond VA','Atlanta GA','Nashville TN','Charlotte NC','Jacksonville FL','Dallas TX','Austin TX','Tampa FL','Houston TX','Los Angeles CA','Seattle WA','Detroit MI','Baltimore MD','Chicago IL','Washington DC','Philadelphia PA'],\n  datasets:[{\n    data:[4.8,5.3,5.7,5.7,5.7,5.8,5.8,5.9,6.2,6.9,7.2,7.5,8.5,10.5,11.3,11.4,13.1,15.7,17.8,18.6],\n    backgroundColor:ctx=>{const v=ctx.raw;return v<6.5?'#2d6a4f':v<9?'#52b788':v<13?'#f4a261':'#e63946'},\n    borderRadius:4\n  }]\n},options:{plugins:{legend:{display:false},tooltip:{callbacks:{label:ctx=>'$'+ctx.raw+'\/1,000 sq ft'}},annotation:{annotations:{avgLine:{type:'line',yMin:6.38,yMax:6.38,borderColor:'#e76f51',borderWidth:1.5,borderDash:[4,3],label:{content:'Nat\\'l avg: $6.38',enabled:true,position:'end',font:{size:10},color:'#e76f51'}}}}},scales:{y:{min:4,ticks:{callback:v=>'$'+v},grid:{color:'#f0f0ea'}},x:{grid:{display:false},ticks:{font:{size:9},maxRotation:45}}}}});\n\n\n\/\/ Frequency donut\nnew Chart(G('freqDonut'),{type:'doughnut',data:{\n  labels:['Biweekly (8-21 days)','Weekly (1-7 days)','Monthly+ (22+ days)'],\n  datasets:[{data:[72.9,13.2,13.9],backgroundColor:['#1b4332','#52b788','#d8f3dc'],borderWidth:0}]\n},options:{cutout:'68%',plugins:{legend:{position:'bottom'}}}});\n\n\/\/ Tip as % of job price \u2014 when a tip is given (20 major markets)\nnew Chart(G('tipPctChart'),{type:'bar',data:{\n  labels:['San Antonio, TX','Chicago, IL','Washington, DC','Fort Worth, TX','Austin, TX','Dallas, TX','Raleigh, NC','Tampa, FL','Knoxville, TN','Richmond, VA','Nashville, TN','St. Louis, MO','Atlanta, GA','Detroit, MI','Houston, TX','Charlotte, NC','Jacksonville, FL','Orlando, FL','Chattanooga, TN','Lakeland, FL'],\n  datasets:[{data:[19.4,18.8,18.7,18.3,18.3,18.3,18.2,18.2,18.1,18.0,17.9,17.8,17.6,17.5,17.2,17.0,16.9,16.8,16.8,16.4],backgroundColor:ctx=>{const v=ctx.raw;return v>=19?'#4a1060':v>=18?'#7b2d8b':v>=17.5?'#9b59b6':'#c39bd3'},borderRadius:5}]\n},options:{\n  plugins:{legend:{display:false},tooltip:{callbacks:{label:ctx=>ctx.raw.toFixed(1)+'% of job price'}},annotation:{annotations:{avgLine:{type:'line',yMin:17.9,yMax:17.9,borderColor:'#e76f51',borderWidth:1.5,borderDash:[4,3],label:{content:'Nat\\'l avg 17.9%',enabled:true,position:'end',font:{size:10},color:'#e76f51'}}}}},\n  scales:{y:{min:15,max:21,ticks:{callback:v=>v+'%'},grid:{color:'#f0f0ea'}},x:{grid:{display:false},ticks:{font:{size:9},maxRotation:45,minRotation:45}}}\n}});\n\n\/\/ (Service charts removed \u2014 sections deleted)\n\n\/\/ Regional pricing chart\nnew Chart(G('regionChart'),{type:'bar',data:{\n  labels:['West','South','Midwest','Northeast'],\n  datasets:[{\n    data:[50.90,52.93,55.45,58.17],\n    backgroundColor:['#52b788','#f4a261','#00b4d8','#e63946'],\n    borderRadius:6\n  }]\n},options:{plugins:{legend:{display:false},tooltip:{callbacks:{label:ctx=>'$'+ctx.raw.toFixed(2)+'\/mow'}},annotation:{annotations:{avgLine:{type:'line',yMin:53.59,yMax:53.59,borderColor:'#e76f51',borderWidth:1.5,borderDash:[4,3],label:{content:'Nat\\'l avg: $53.59',enabled:true,position:'end',font:{size:10},color:'#e76f51'}}}}},scales:{y:{min:48,ticks:{callback:v=>'$'+v},grid:{color:'#f0f0ea'}},x:{grid:{display:false}}}}});\n\n\/\/ Annual cost by market (sorted high to low, verified from sheet col AG)\nnew Chart(G('annualCostChart'),{type:'bar',data:{\n  labels:['Orlando FL','New Orleans LA','Lakeland FL','Knoxville TN','Chattanooga TN','Tampa FL','Virginia Beach VA','Austin TX','Nashville TN','Dallas TX','St. Louis MO','Minneapolis MN','Pittsburgh PA','Chicago IL','Atlanta GA','Cleveland OH','Memphis TN','Baltimore MD','Philadelphia PA','Detroit MI'],\n  datasets:[{label:'Annual Cost',data:[576,553,549,538,532,509,505,495,487,479,370,364,360,355,340,328,324,309,287,258],backgroundColor:'#2d6a4f',borderRadius:4}]\n},options:{\n  indexAxis:'y',\n  plugins:{legend:{display:false},tooltip:{callbacks:{label:ctx=>'$'+ctx.raw+'\/yr'}},annotation:{annotations:{avgLine:{type:'line',xMin:407,xMax:407,borderColor:'#e76f51',borderWidth:1.5,borderDash:[4,3],label:{content:'Nat\\'l avg: $407',enabled:true,position:'end',font:{size:10},color:'#e76f51'}}}}},\n  scales:{x:{min:240,ticks:{callback:v=>'$'+v},grid:{color:'#f0f0ea'}},y:{grid:{display:false},ticks:{font:{size:10}}}}\n}});\n\n\/\/ Tip Rate \u2014 20 major markets (sorted high to low by tip rate)\nnew Chart(G('tipRateMajorChart'),{type:'bar',data:{\n  labels:['Knoxville','St. Louis','Nashville','Richmond','Chattanooga','Raleigh','San Antonio','Charlotte','Austin','Ft. Worth','Jacksonville','Dallas','Detroit','Houston','Atlanta','DC','Chicago','Tampa','Lakeland','Orlando'],\n  datasets:[{\n    data:[32.2,31.0,30.5,30.4,29.4,27.9,27.3,26.7,24.9,23.8,23.8,22.8,22.6,21.8,21.5,21.0,20.5,20.3,19.5,17.6],\n    backgroundColor:ctx=>{const v=ctx.raw;return v>=29?'#1b4332':v>=26?'#2d6a4f':v>=23?'#52b788':v>=20?'#d97706':'#c0392b'},\n    borderRadius:5\n  }]\n},options:{plugins:{legend:{display:false},tooltip:{callbacks:{label:ctx=>ctx.raw.toFixed(1)+'% tip rate'}},annotation:{annotations:{avgLine:{type:'line',yMin:24.8,yMax:24.8,borderColor:'#e76f51',borderWidth:1.5,borderDash:[4,3],label:{content:'Major-market avg: 24.8%',enabled:true,position:'end',font:{size:10},color:'#e76f51'}}}}},scales:{y:{min:14,max:34,ticks:{callback:v=>v+'%'},grid:{color:'#f0f0ea'}},x:{grid:{display:false},ticks:{font:{size:9},maxRotation:40,minRotation:40,autoSkip:false}}}}});\n\n\/\/ Avg Tip Amount \u2014 20 major markets (sorted high to low by amount)\nnew Chart(G('tipAmtMajorChart'),{type:'bar',data:{\n  labels:['Chattanooga','Knoxville','Richmond','Nashville','San Antonio','Chicago','Charlotte','Raleigh','St. Louis','Atlanta','DC','Austin','Ft. Worth','Tampa','Lakeland','Dallas','Detroit','Jacksonville','Orlando','Houston'],\n  datasets:[{\n    data:[11.68,10.54,10.50,10.11,9.95,9.73,9.51,9.49,9.44,9.34,9.04,8.99,8.98,8.92,8.91,8.76,8.75,8.61,8.25,7.92],\n    backgroundColor:ctx=>{const v=ctx.raw;return v>=10.5?'#003f5c':v>=9.5?'#005f73':v>=9.2?'#0077b6':v>=8.8?'#48cae4':'#90e0ef'},\n    borderRadius:5\n  }]\n},options:{plugins:{legend:{display:false},tooltip:{callbacks:{label:ctx=>'$'+ctx.raw.toFixed(2)+' avg tip'}},annotation:{annotations:{avgLine:{type:'line',yMin:9.37,yMax:9.37,borderColor:'#e76f51',borderWidth:1.5,borderDash:[4,3],label:{content:'Major-market avg: $9.37',enabled:true,position:'end',font:{size:10},color:'#e76f51'}}}}},scales:{y:{min:7.5,max:12.5,ticks:{callback:v=>'$'+v.toFixed(2)},grid:{color:'#f0f0ea'}},x:{grid:{display:false},ticks:{font:{size:9},maxRotation:40,minRotation:40,autoSkip:false}}}}});\n\n\/\/ Effective Tip Per Mow \u2014 20 major markets (sorted high to low)\nnew Chart(G('effTipMajorChart'),{type:'bar',data:{\n  labels:['Chattanooga','Knoxville','Richmond','Nashville','St. Louis','San Antonio','Raleigh','Charlotte','Austin','Ft. Worth','DC','Jacksonville','Atlanta','Dallas','Chicago','Detroit','Tampa','Houston','Lakeland','Orlando'],\n  datasets:[{label:'$\/mow',\n    data:[3.47,3.41,3.13,3.05,2.87,2.70,2.65,2.54,2.24,2.14,2.10,2.05,2.01,2.00,1.98,1.98,1.81,1.78,1.72,1.45],\n    backgroundColor:ctx=>{const v=ctx.raw;return v>=3.0?'#7b1d1d':v>=2.6?'#b5451b':v>=2.2?'#e76f51':v>=2.0?'#f4a261':'#fcd6bc'},\n    borderRadius:5\n  }]\n},options:{plugins:{legend:{display:false},tooltip:{callbacks:{label:ctx=>'$'+ctx.raw.toFixed(2)+'\/mow'}},annotation:{annotations:{avgLine:{type:'line',yMin:2.35,yMax:2.35,borderColor:'#0077b6',borderWidth:1.5,borderDash:[4,3],label:{content:'Major-market avg: $2.35\/mow',enabled:true,position:'end',font:{size:10},color:'#0077b6'}}}}},scales:{y:{min:1.3,max:3.8,ticks:{callback:v=>'$'+v.toFixed(2)},grid:{color:'#f0f0ea'}},x:{grid:{display:false},ticks:{font:{size:9},maxRotation:40,minRotation:40}}}}});\n\n\/\/ Scatter chart \u2014 Tip Rate vs Avg Tip Amount (major markets)\n(function(){\n  const data = [\n    {city:'St. Louis, MO',    rate:31.0, eff:2.87, amt:9.44},\n    {city:'Raleigh, NC',      rate:27.9, eff:2.65, amt:9.49},\n    {city:'San Antonio, TX',  rate:27.3, eff:2.70, amt:9.95},\n    {city:'Charlotte, NC',    rate:26.7, eff:2.54, amt:9.51},\n    {city:'Austin, TX',       rate:24.9, eff:2.24, amt:8.99},\n    {city:'Fort Worth, TX',   rate:23.8, eff:2.14, amt:8.98},\n    {city:'Jacksonville, FL', rate:23.8, eff:2.05, amt:8.61},\n    {city:'Dallas, TX',       rate:22.8, eff:2.00, amt:8.76},\n    {city:'Detroit, MI',      rate:22.6, eff:1.98, amt:8.75},\n    {city:'Houston, TX',      rate:21.8, eff:1.78, amt:7.92},\n    {city:'Atlanta, GA',      rate:21.5, eff:2.01, amt:9.34},\n    {city:'Washington, DC',   rate:21.0, eff:2.10, amt:9.04},\n    {city:'Chicago, IL',      rate:20.5, eff:1.98, amt:9.73},\n    {city:'Tampa, FL',        rate:20.3, eff:1.81, amt:8.92},\n    {city:'Orlando, FL',      rate:17.6, eff:1.45, amt:8.25},\n    {city:'Knoxville, TN',    rate:32.2, eff:3.41, amt:10.54},\n    {city:'Chattanooga, TN',  rate:29.4, eff:3.47, amt:11.68},\n    {city:'Richmond, VA',     rate:30.4, eff:3.13, amt:10.50},\n    {city:'Nashville, TN',    rate:30.5, eff:3.05, amt:10.11},\n    {city:'Lakeland, FL',     rate:19.5, eff:1.72, amt:8.91},\n  ];\n\n  \/\/ Larger canvas for breathing room \u2014 all label positions verified against dot coordinates\n  const W=880, H=520, ml=80, mr=60, mt=70, mb=65;\n  const pw=W-ml-mr, ph=H-mt-mb; \/\/ pw=740, ph=385\n\n  const cont = document.getElementById('scatterChart');\n  if(!cont) return;\n\n  const svg = d3.select(cont).append('svg')\n    .attr('viewBox',`0 0 ${W} ${H}`)\n    .style('width','100%').style('display','block');\n\n  const g = svg.append('g').attr('transform',`translate(${ml},${mt})`);\n\n  const xSc = d3.scaleLinear().domain([15,35]).range([0,pw]);\n  const ySc = d3.scaleLinear().domain([7.00,12.80]).range([ph,0]);\n\n  const qx=24.8, qy=9.37;\n  const qxp=xSc(qx), qyp=ySc(qy);\n\n  \/\/ Quadrant backgrounds\n  const quads=[\n    {x:qxp, y:0,    w:pw-qxp,  h:qyp,    fill:'#f0fdf4', lbl:'HIGH TIP RATE + HIGH TIPS',  lx:qxp+(pw-qxp)\/2, ly:16},\n    {x:0,   y:0,    w:qxp,     h:qyp,    fill:'#eff6ff', lbl:'LOW TIP RATE, HIGH TIPS',     lx:qxp\/2,           ly:16},\n    {x:qxp, y:qyp,  w:pw-qxp,  h:ph-qyp, fill:'#fffbeb', lbl:'HIGH TIP RATE, LOW TIPS',     lx:qxp+(pw-qxp)\/2, ly:ph-10},\n    {x:0,   y:qyp,  w:qxp,     h:ph-qyp, fill:'#fff1f2', lbl:'LOW TIP RATE + LOW TIPS',     lx:qxp\/2,           ly:ph-10},\n  ];\n  quads.forEach(q=>{\n    g.append('rect').attr('x',q.x).attr('y',q.y).attr('width',q.w).attr('height',q.h)\n      .attr('fill',q.fill).attr('opacity',0.8);\n    g.append('text').attr('x',q.lx).attr('y',q.ly)\n      .attr('text-anchor','middle').attr('font-size','11')\n      .attr('fill','#999').attr('font-family','\"Courier New\",monospace')\n      .attr('letter-spacing','0.5').text(q.lbl);\n  });\n\n  \/\/ Quadrant divider lines\n  g.append('line').attr('x1',qxp).attr('y1',0).attr('x2',qxp).attr('y2',ph)\n    .attr('stroke','#ccc').attr('stroke-width',1).attr('stroke-dasharray','4,3');\n  g.append('line').attr('x1',0).attr('y1',qyp).attr('x2',pw).attr('y2',qyp)\n    .attr('stroke','#ccc').attr('stroke-width',1).attr('stroke-dasharray','4,3');\n\n  \/\/ Axis midpoint reference labels\n  g.append('text').attr('x',qxp).attr('y',ph+30)\n    .attr('text-anchor','middle').attr('font-size','10').attr('fill','#bbb')\n    .attr('font-family','\"Courier New\",monospace').text('avg 24.8%');\n  g.append('text').attr('x',-8).attr('y',qyp+4)\n    .attr('text-anchor','end').attr('font-size','10').attr('fill','#bbb')\n    .attr('font-family','\"Courier New\",monospace').text('$9.37');\n\n  \/\/ Axes\n  g.append('g').attr('transform',`translate(0,${ph})`).call(\n    d3.axisBottom(xSc).ticks(6).tickFormat(d=>d+'%')\n  ).call(ax=>{\n    ax.select('.domain').attr('stroke','#ddd');\n    ax.selectAll('.tick line').attr('stroke','#ddd');\n    ax.selectAll('text').attr('font-size','12').attr('fill','#666').attr('font-family','Georgia,serif');\n  });\n  g.append('g').call(\n    d3.axisLeft(ySc).ticks(6).tickFormat(d=>'$'+d.toFixed(2))\n  ).call(ax=>{\n    ax.select('.domain').attr('stroke','#ddd');\n    ax.selectAll('.tick line').attr('stroke','#ddd');\n    ax.selectAll('text').attr('font-size','12').attr('fill','#666').attr('font-family','Georgia,serif');\n  });\n\n  \/\/ Axis titles\n  g.append('text').attr('x',pw\/2).attr('y',ph+50)\n    .attr('text-anchor','middle').attr('font-size','13').attr('fill','#555')\n    .attr('font-family','Georgia,serif').text('Tip Rate (% of mows tipped)');\n  g.append('text').attr('transform','rotate(-90)').attr('x',-ph\/2).attr('y',-60)\n    .attr('text-anchor','middle').attr('font-size','13').attr('fill','#555')\n    .attr('font-family','Georgia,serif').text('Avg Tip Amount (when given)');\n\n  \/\/ Color by quadrant\n  function col(d){\n    if(d.rate>=qx && d.amt>=qy) return '#2d6a4f';  \/\/ green: high tip rate + high tips\n    if(d.rate< qx && d.amt>=qy) return '#1d7fa6';  \/\/ blue: low tip rate, high tips\n    if(d.rate>=qx && d.amt< qy) return '#d97706';  \/\/ amber: high tip rate, low tips\n    return '#c0392b';                                \/\/ red: low tip rate + low tips\n  }\n\n  \/\/ Hover tooltip card (SVG overlay)\n  const tipG = svg.append('g').style('display','none').style('pointer-events','none');\n  const tipBg = tipG.append('rect').attr('rx',7).attr('fill','rgba(10,18,12,0.91)').attr('stroke','rgba(255,255,255,0.15)').attr('stroke-width',1);\n  tipG.append('rect').attr('class','tip-accent').attr('width',3).attr('rx',1.5);\n  const tipCity = tipG.append('text').attr('font-size','13').attr('font-weight','700').attr('fill','#fff').attr('font-family','Georgia,serif');\n  const tipR    = tipG.append('text').attr('font-size','11').attr('fill','#a8d5b5').attr('font-family','\"Courier New\",monospace');\n  const tipA    = tipG.append('text').attr('font-size','11').attr('fill','#a8d5b5').attr('font-family','\"Courier New\",monospace');\n  const tipE    = tipG.append('text').attr('font-size','11.5').attr('font-weight','700').attr('fill','#f4c542').attr('font-family','\"Courier New\",monospace');\n\n  function showTip(d,cx,cy){\n    const bw=186,bh=78,pad=11,lh=16;\n    let tx=cx+ml+16, ty=cy+mt-bh\/2;\n    if(tx+bw>W-4) tx=cx+ml-bw-16;\n    if(ty<4) ty=4;\n    if(ty+bh>H-4) ty=H-bh-4;\n    tipG.style('display','').attr('transform',`translate(${tx},${ty})`);\n    tipBg.attr('width',bw).attr('height',bh);\n    tipG.select('.tip-accent').attr('height',bh).attr('fill',col(d));\n    tipCity.attr('x',pad+6).attr('y',pad+13).text(d.city);\n    tipR.attr('x',pad+6).attr('y',pad+13+lh).text('Tip rate: '+d.rate+'%');\n    tipA.attr('x',pad+6).attr('y',pad+13+lh*2).text('Avg tip:  $'+d.amt.toFixed(2));\n    tipE.attr('x',pad+6).attr('y',pad+13+lh*3).text('Earns $'+d.eff.toFixed(2)+'\/mow');\n  }\n  function hideTip(){ tipG.style('display','none'); }\n\n  \/\/ Five key cities get always-visible static labels.\n  \/\/ Positions verified against actual dot coords (pw=740, ph=385) \u2014 no overlap with any label.\n  \/\/   Chattanooga (cx\u2248533, cy\u224874):  UP-LEFT    \u2014 dx:-66, dy:-30  (box right \u2248469, quad label starts \u2248477)\n  \/\/   San Antonio (cx\u2248455, cy\u2248189): UP-LEFT    \u2014 dx:-22, dy:-40\n  \/\/   Chicago     (cx\u2248204, cy\u2248204): UP-LEFT    \u2014 dx:-20, dy:-26\n  \/\/   Houston     (cx\u2248252, cy\u2248324): LOWER      \u2014 dx:12,  dy:35   (box right \u2248466, quad label starts \u2248477)\n  \/\/   Orlando     (cx\u224896,  cy\u2248301): BELOW      \u2014 dx:0,   dy:40\n  const ann=[\n    {city:'Chattanooga, TN', lbl:'Chattanooga', sub:'$3.47\/mow \\u2014 best overall',   dx:-66, dy:-30, anc:'end',    bw:162},\n    {city:'San Antonio, TX', lbl:'San Antonio', sub:'High rate & big tips: $9.95',      dx:-22, dy:-40, anc:'end',    bw:180},\n    {city:'Chicago, IL',     lbl:'Chicago',     sub:'Low rate, big tips: $9.73',        dx:-20, dy:-26, anc:'end',    bw:168},\n    {city:'Houston, TX',     lbl:'Houston',     sub:'Lowest avg tip: $7.92',             dx:12,  dy:35,  anc:'start',  bw:148},\n    {city:'Orlando, FL',     lbl:'Orlando',     sub:'$1.45\/mow \\u2014 toughest market', dx:0,   dy:40,  anc:'middle', bw:180},\n  ];\n  const standouts = new Set(ann.map(a=>a.city));\n\n  \/\/ Non-standout dots \u2014 with city name labels (20 cities total, smart-offset to avoid overlaps)\n  const lblOff={\n    'Raleigh, NC':      {dx:8,  dy:-9},   \/\/ up \u2014 away from Charlotte\n    'Charlotte, NC':    {dx:8,  dy:15},   \/\/ down \u2014 away from Raleigh\n    'Austin, TX':       {dx:8,  dy:-9},   \/\/ up \u2014 away from Fort Worth\n    'Fort Worth, TX':   {dx:8,  dy:15},   \/\/ down \u2014 away from Austin\n    'Dallas, TX':       {dx:6,  dy:-14},  \/\/ above the dot \u2014 clear of Detroit cluster below\n    'Detroit, MI':      {dx:-10, dy:12},  \/\/ left \u2014 away from Dallas cluster\n    'Washington, DC':   {dx:-10, dy:-9},  \/\/ left+up \u2014 clear of Tampa\/Atlanta\n    'Tampa, FL':        {dx:8,  dy:15},   \/\/ down \u2014 avoid DC\n    'Atlanta, GA':      {dx:8,  dy:-9},   \/\/ up\n    'Jacksonville, FL': {dx:8,  dy:15},   \/\/ below-right\n    'Knoxville, TN':    {dx:8,  dy:-10},  \/\/ up-right\n    'Richmond, VA':     {dx:-6, dy:14},   \/\/ below-left (separate from Knoxville)\n    'Nashville, TN':    {dx:8,  dy:8},    \/\/ right + slightly below\n    'St. Louis, MO':    {dx:8,  dy:-9},   \/\/ up-right (was standout; now regular dot)\n    'Lakeland, FL':     {dx:-8, dy:16},   \/\/ below-left (avoids quadrant title)\n  };\n  const shortN={'Washington, DC':'DC','Fort Worth, TX':'Ft. Worth','Jacksonville, FL':'Jacksonville'};\n  data.filter(d=>!standouts.has(d.city)).forEach(d=>{\n    const cx=xSc(d.rate), cy=ySc(d.amt), c=col(d);\n    const off=lblOff[d.city]||{dx:8,dy:4};\n    const lbl=shortN[d.city]||d.city.split(',')[0];\n    g.append('circle').attr('cx',cx).attr('cy',cy).attr('r',5.5)\n      .attr('fill',c).attr('opacity',0.5).attr('stroke','#fff').attr('stroke-width',1)\n      .style('cursor','pointer')\n      .on('mouseenter',function(){d3.select(this).attr('r',8.5).attr('opacity',0.9);showTip(d,cx,cy);})\n      .on('mouseleave',function(){d3.select(this).attr('r',5.5).attr('opacity',0.5);hideTip();});\n    g.append('text').attr('x',cx+off.dx).attr('y',cy+off.dy)\n      .attr('font-size','9.5').attr('fill','#555').attr('font-family','Georgia,serif')\n      .attr('text-anchor',off.dx<0?'end':'start')\n      .text(lbl);\n  });\n\n  \/\/ Standout dots + always-visible labels\n  ann.forEach(function(a){\n    var d=data.find(function(x){return x.city===a.city;}); if(!d) return;\n    var cx=xSc(d.rate), cy=ySc(d.amt), c=col(d);\n    var tx=cx+a.dx, ty=cy+a.dy;\n\n    \/\/ Subtle outer ring for standout cities\n    g.append('circle').attr('cx',cx).attr('cy',cy).attr('r',14)\n      .attr('fill','none').attr('stroke',c).attr('stroke-width',1).attr('opacity',0.25);\n    \/\/ Main dot\n    g.append('circle').attr('cx',cx).attr('cy',cy).attr('r',9)\n      .attr('fill',c).attr('opacity',1).attr('stroke','#fff').attr('stroke-width',2.5)\n      .style('cursor','pointer')\n      .on('mouseenter',function(){d3.select(this).attr('r',12);showTip(d,cx,cy);})\n      .on('mouseleave',function(){d3.select(this).attr('r',9);hideTip();});\n    \/\/ Leader line from dot to label\n    g.append('line').attr('x1',cx).attr('y1',cy).attr('x2',tx).attr('y2',ty)\n      .attr('stroke',c).attr('stroke-width',1.2).attr('opacity',0.55);\n\n    \/\/ Label box\n    var bw=a.bw, bh=38;\n    var bx = a.anc==='middle' ? tx-bw\/2 : a.anc==='end' ? tx-bw : tx;\n    g.append('rect').attr('x',bx-2).attr('y',ty-26)\n      .attr('width',bw+4).attr('height',bh)\n      .attr('fill','rgba(255,255,255,0.97)').attr('rx',5)\n      .attr('stroke',c).attr('stroke-width',1.8);\n    \/\/ Left color accent bar on label box\n    g.append('rect').attr('x',bx-2).attr('y',ty-26).attr('width',4).attr('height',bh)\n      .attr('fill',c).attr('rx',3);\n\n    var textX = a.anc==='middle' ? tx : a.anc==='end' ? tx-7 : tx+7;\n    var textAnc = a.anc==='middle' ? 'middle' : a.anc;\n    \/\/ City name\n    g.append('text').attr('x',textX).attr('y',ty-10)\n      .attr('text-anchor',textAnc).attr('font-size','13').attr('font-weight','700')\n      .attr('fill',c).attr('font-family','Georgia,serif').text(a.lbl);\n    \/\/ Stat line\n    g.append('text').attr('x',textX).attr('y',ty+6)\n      .attr('text-anchor',textAnc).attr('font-size','10.5').attr('fill','#444')\n      .attr('font-family','\"Courier New\",monospace').text(a.sub);\n  });\n\n  \/\/ Tooltip renders on top of everything\n  svg.node().appendChild(tipG.node());\n\n})();\n\n\/\/ \u2500\u2500 TIPPING YEAR-OVER-YEAR CHARTS (2024 \u2192 2025) \u2500\u2500\u2500\u2500\u2500\u2500\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\/\/ 20 major markets; same cities used throughout the report.\n\n\/\/ Tip Rate % change \u2014 sorted by magnitude (all positive)\nnew Chart(G('yoyRateChart'),{type:'bar',data:{\n  labels:['Nashville','St. Louis','Chattanooga','Austin','Raleigh','Charlotte','San Antonio','Richmond','DC','Dallas','Houston','Lakeland','Jacksonville','Ft. Worth','Knoxville','Tampa','Atlanta','Chicago','Orlando','Detroit'],\n  datasets:[{\n    data:[10.76,10.41,9.74,9.36,8.86,8.66,8.52,8.48,8.15,8.04,7.38,7.22,7.16,6.98,6.62,5.88,5.80,5.78,5.35,4.80],\n    backgroundColor:ctx=>{const v=ctx.raw;return v>=10?'#0a2e1a':v>=9?'#1b4332':v>=8?'#2d6a4f':v>=7?'#52b788':'#95d5b2'},\n    borderRadius:5\n  }]\n},options:{\n  indexAxis:'y',\n  plugins:{\n    legend:{display:false},\n    tooltip:{callbacks:{label:ctx=>'+'+ctx.raw.toFixed(2)+' percentage points vs 2024'}},\n    annotation:{annotations:{avgLine:{type:'line',xMin:7.61,xMax:7.61,borderColor:'#f4c542',borderWidth:1.5,borderDash:[4,3],label:{content:'National avg: +7.6 pts',enabled:true,position:'end',font:{size:10},color:'#f4c542'}}}}\n  },\n  scales:{\n    x:{min:0,max:12,ticks:{callback:v=>v===0?'0':'+'+v+' pts'},grid:{color:'#f0f0ea'}},\n    y:{grid:{display:false},ticks:{font:{size:9}}}\n  }\n}});\n\n\/\/ Avg Tip $ change \u2014 sorted high to low (diverging; 10 positive, 9 negative, 1 flat)\nnew Chart(G('yoyAmtChart'),{type:'bar',data:{\n  labels:['Chicago','Tampa','Ft. Worth','Charlotte','Richmond','Atlanta','Dallas','San Antonio','Nashville','Lakeland','DC','Raleigh','St. Louis','Orlando','Austin','Jacksonville','Knoxville','Houston','Chattanooga','Detroit'],\n  datasets:[{\n    data:[0.47,0.32,0.31,0.27,0.24,0.14,0.13,0.12,0.09,0.05,0.00,-0.02,-0.05,-0.10,-0.15,-0.16,-0.27,-0.33,-0.52,-0.54],\n    backgroundColor:ctx=>{const v=ctx.raw;return v>0.2?'#2d6a4f':v>0?'#52b788':v===0?'#aaaaaa':v>-0.2?'#f4a261':'#e76f51'},\n    borderRadius:5\n  }]\n},options:{\n  indexAxis:'y',\n  plugins:{\n    legend:{display:false},\n    tooltip:{callbacks:{label:ctx=>(ctx.raw>0?'+$':ctx.raw<0?'-$':'$')+Math.abs(ctx.raw).toFixed(2)+' vs 2024'}},\n    annotation:{annotations:{zeroLine:{type:'line',xMin:0,xMax:0,borderColor:'rgba(0,0,0,.2)',borderWidth:1.5},avgLine:{type:'line',xMin:0.14,xMax:0.14,borderColor:'#95d5b2',borderWidth:1.5,borderDash:[4,3],label:{content:'National avg: +$0.14',enabled:true,position:'end',font:{size:10},color:'#95d5b2'}}}}\n  },\n  scales:{\n    x:{min:-0.7,max:0.6,ticks:{callback:v=>v>0?'+$'+v.toFixed(2):v<0?'-$'+Math.abs(v).toFixed(2):'$0'},grid:{color:'#f0f0ea'}},\n    y:{grid:{display:false},ticks:{font:{size:9}}}\n  }\n}});\n\n\/\/ Tip as % of Job \u2014 grouped bar: 2024 (amber) vs 2025 (green), sorted by 2025 value desc\nnew Chart(G('yoyPctChart'),{type:'bar',data:{\n  labels:['San Antonio','Chicago','DC','Austin','Knoxville','Ft. Worth','Dallas','Atlanta','Richmond','Raleigh','Nashville','Tampa','St. Louis','Houston','Detroit','Charlotte','Orlando','Jacksonville','Chattanooga','Lakeland'],\n  datasets:[\n    {label:'2024',\n     data:[20.23,19.25,19.27,19.53,19.52,18.61,18.42,18.32,18.43,19.06,18.50,18.08,18.86,18.65,19.27,17.73,17.90,17.96,18.92,17.03],\n     backgroundColor:'rgba(244,194,97,0.65)',borderColor:'#f4c262',borderWidth:1,borderRadius:3},\n    {label:'2025',\n     data:[19.05,18.77,18.67,18.42,18.15,18.07,18.04,17.97,17.96,17.91,17.85,17.76,17.75,17.27,17.22,17.04,16.94,16.88,16.77,16.35],\n     backgroundColor:ctx=>{const v=ctx.raw;return v>=18.5?'#1b4332':v>=17.5?'#2d6a4f':'#52b788'},borderRadius:3}\n  ]\n},options:{\n  indexAxis:'y',\n  plugins:{\n    legend:{display:true,position:'bottom'},\n    tooltip:{callbacks:{label:ctx=>ctx.dataset.label+': '+ctx.raw.toFixed(2)+'% of job'}},\n    annotation:{annotations:{\n      avg25:{type:'line',xMin:17.89,xMax:17.89,borderColor:'#95d5b2',borderWidth:1.5,borderDash:[4,3],\n             label:{content:\"2025 nat'l avg: 17.9%\",enabled:true,position:'start',font:{size:10},color:'#95d5b2'}},\n      avg24:{type:'line',xMin:18.61,xMax:18.61,borderColor:'#f4c262',borderWidth:1.5,borderDash:[4,3],\n             label:{content:\"2024 nat'l avg: 18.6%\",enabled:true,position:'end',font:{size:10},color:'#f4c262'}}\n    }}\n  },\n  scales:{\n    x:{min:15,max:22,ticks:{callback:v=>v+'%'},grid:{color:'#f0f0ea'}},\n    y:{grid:{display:false},ticks:{font:{size:9}}}\n  }\n}});\n\n\/\/ \u2500\u2500 YoY TIPPING STATE MAP \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\/\/ Color: deep-green = rate+$ both strongly up, medium-green = both up,\n\/\/        light-green = rate up \/ $ flat, amber = rate up \/ $ fell, red = rate fell.\n\/\/ HI excluded (single city with extreme anomalous -32.97pp swing).\n(function(){\n  var tipYoYData={\n    AL:{rc:8.35,ac:0.35,pc:-0.56,r24:22.69},  AR:{rc:7.95,ac:0.07,pc:-0.98,r24:21.47},\n    AZ:{rc:5.24,ac:-1.82,pc:-4.60,r24:24.94}, CA:{rc:8.14,ac:-0.15,pc:-0.75,r24:19.53},\n    CO:{rc:9.54,ac:0.42,pc:-0.68,r24:23.81},  CT:{rc:7.05,ac:0.21,pc:-0.64,r24:20.97},\n    DC:{rc:8.15,ac:0.00,pc:-0.60,r24:12.96},  DE:{rc:7.99,ac:0.14,pc:-0.81,r24:20.20},\n    FL:{rc:6.92,ac:0.06,pc:-0.64,r24:15.98},  GA:{rc:6.56,ac:0.41,pc:-0.41,r24:18.02},\n    IA:{rc:9.73,ac:0.32,pc:-0.11,r24:22.75},  ID:{rc:5.15,ac:-0.57,pc:-1.28,r24:27.76},\n    IL:{rc:6.40,ac:0.40,pc:-0.45,r24:17.95},  IN:{rc:6.54,ac:0.10,pc:-0.59,r24:21.82},\n    KS:{rc:8.22,ac:0.13,pc:-0.09,r24:23.73},  KY:{rc:9.17,ac:0.42,pc:0.14,r24:21.30},\n    LA:{rc:7.65,ac:0.13,pc:-0.74,r24:18.40},  MA:{rc:5.85,ac:0.44,pc:0.28,r24:23.07},\n    MD:{rc:8.14,ac:0.30,pc:-0.47,r24:18.12},  ME:{rc:2.63,ac:-3.41,pc:-5.51,r24:26.17},\n    MI:{rc:5.73,ac:-0.81,pc:-2.21,r24:21.74}, MN:{rc:6.75,ac:-0.58,pc:-2.29,r24:25.45},\n    MO:{rc:8.29,ac:0.31,pc:-0.48,r24:21.27},  MS:{rc:4.87,ac:0.63,pc:0.36,r24:21.43},\n    NC:{rc:7.76,ac:0.45,pc:-0.44,r24:20.17},  ND:{rc:-3.18,ac:-1.23,pc:-5.22,r24:47.37},\n    NE:{rc:9.24,ac:0.28,pc:-0.26,r24:25.17},  NH:{rc:16.60,ac:0.04,pc:0.34,r24:24.78},\n    NJ:{rc:4.36,ac:0.06,pc:-0.95,r24:20.90},  NM:{rc:33.95,ac:0.41,pc:0.14,r24:27.29},\n    NV:{rc:13.18,ac:-0.51,pc:-1.71,r24:19.74},NY:{rc:6.52,ac:0.45,pc:0.08,r24:20.89},\n    OH:{rc:7.63,ac:-0.16,pc:-1.06,r24:20.90}, OK:{rc:7.60,ac:0.12,pc:-0.75,r24:22.86},\n    OR:{rc:6.77,ac:0.00,pc:-0.89,r24:26.19},  PA:{rc:8.40,ac:0.39,pc:-0.67,r24:21.31},\n    RI:{rc:6.34,ac:-0.09,pc:-0.99,r24:26.27}, SC:{rc:7.17,ac:0.38,pc:-0.62,r24:21.14},\n    SD:{rc:12.52,ac:-0.33,pc:-1.18,r24:20.45},TN:{rc:7.96,ac:0.10,pc:-0.90,r24:21.99},\n    TX:{rc:8.15,ac:0.08,pc:-0.76,r24:16.98},  UT:{rc:3.77,ac:0.57,pc:-0.03,r24:27.01},\n    VA:{rc:8.44,ac:0.34,pc:-0.58,r24:20.02},  VT:{rc:5.43,ac:0.20,pc:-0.79,r24:40.91},\n    WA:{rc:7.52,ac:0.03,pc:-0.68,r24:26.05},  WI:{rc:8.93,ac:0.10,pc:-1.03,r24:23.63},\n    WV:{rc:-2.16,ac:0.31,pc:-0.39,r24:37.79}\n  };\n  function tipColor(d){\n    if(d.rc<=0)return'#e63946';\n    if(d.rc>8&&d.ac>0.30)return'#1b4332';\n    if(d.ac>0)return'#2d6a4f';\n    if(d.ac>=-0.10)return'#52b788';\n    return'#f4a261';\n  }\n  function tipLabel(d){var rel=d.r24?d.rc\/d.r24*100:0;return(rel>=0?'+':'')+Math.round(rel)+'%';}\n  function tipTip(abbr,d){\n    var rel=d.r24?d.rc\/d.r24*100:0;\n    var relStr=(rel>=0?'+':'')+Math.round(rel)+'%';\n    var ptStr=(d.rc>0?'+':'')+d.rc.toFixed(2)+' pts';\n    var ac=(d.ac>=0?'+$':'\\u2212$')+Math.abs(d.ac).toFixed(2);\n    var pc=(d.pc>0?'+':'')+d.pc.toFixed(2)+' pts';\n    return'<strong>'+(SN[abbr]||abbr)+'<\/strong>: Tip rate '+relStr+' ('+ptStr+')&nbsp;&middot;&nbsp;Avg tip '+ac+'&nbsp;&middot;&nbsp;% of bill '+pc;\n  }\n  var el=document.getElementById('tipYoYMap');if(!el)return;\n  var W=960,H=600,ns='http:\/\/www.w3.org\/2000\/svg';\n  var svg=document.createElementNS(ns,'svg');\n  svg.setAttribute('viewBox','0 0 '+W+' '+H);\n  svg.setAttribute('style','width:100%;height:auto;display:block;border-radius:8px');\n  var bg=document.createElementNS(ns,'rect');\n  bg.setAttribute('width',W);bg.setAttribute('height',H);bg.setAttribute('fill','#eef2f0');bg.setAttribute('rx','8');svg.appendChild(bg);\n  var tt=_getTt();\n  _getAtlas().then(function(us){\n    var states=topojson.feature(us,us.objects.states);\n    var proj=d3.geoAlbersUsa().scale(1280).translate([W\/2,H\/2]);\n    var path=d3.geoPath().projection(proj);\n    var small=new Set(['CT','RI','DE','DC','NJ','MD','MA','VT','NH','ME']);\n    var smallC={};\n    states.features.forEach(function(f){\n      var fips=String(f.id).padStart(2,'0');\n      var abbr=_fipsMap[fips];if(!abbr)return;\n      var d=tipYoYData[abbr];\n      var pd=path(f);if(!pd)return;\n      var pe=document.createElementNS(ns,'path');\n      pe.setAttribute('d',pd);\n      pe.setAttribute('fill',d!=null?tipColor(d):'#d8dbd6');\n      pe.setAttribute('stroke','#fff');pe.setAttribute('stroke-width','0.6');\n      pe.style.cursor='pointer';pe.style.transition='filter .12s';\n      pe.addEventListener('mouseover',function(){pe.style.filter='brightness(1.15)';tt.style.opacity='1';tt.innerHTML=d!=null?tipTip(abbr,d):'<strong>'+(SN[abbr]||abbr)+'<\/strong>: No data';});\n      pe.addEventListener('mousemove',function(e){tt.style.left=(e.clientX+14)+'px';tt.style.top=(e.clientY-36)+'px';});\n      pe.addEventListener('mouseout',function(){pe.style.filter='';tt.style.opacity='0';});\n      svg.appendChild(pe);\n      var _cFix={MI:[673,176],FL:[770,508],WV:[758,274],HI:[272,545]};\n      var c=_cFix[abbr]||path.centroid(f);\n      if(c&&!isNaN(c[0])&&!isNaN(c[1])){\n        if(small.has(abbr)){smallC[abbr]=c;}\n        else{\n          var tx=document.createElementNS(ns,'text');\n          tx.setAttribute('x',c[0]);tx.setAttribute('y',d!=null?c[1]-9:c[1]);\n          tx.setAttribute('text-anchor','middle');tx.setAttribute('dominant-baseline','middle');\n          tx.setAttribute('font-size','14');tx.setAttribute('font-family','\"Courier New\",monospace');\n          tx.setAttribute('font-weight','700');tx.setAttribute('fill',d!=null?'#fff':'#999');\n          tx.setAttribute('pointer-events','none');tx.textContent=abbr;svg.appendChild(tx);\n          if(d!=null){\n            var vx=document.createElementNS(ns,'text');\n            vx.setAttribute('x',c[0]);vx.setAttribute('y',c[1]+12);\n            vx.setAttribute('text-anchor','middle');vx.setAttribute('dominant-baseline','middle');\n            vx.setAttribute('font-size','11');vx.setAttribute('font-family','\"Courier New\",monospace');\n            vx.setAttribute('fill','rgba(255,255,255,0.95)');vx.setAttribute('pointer-events','none');\n            vx.textContent=tipLabel(d);svg.appendChild(vx);\n          }\n        }\n      }\n    });\n    var neList=['ME','NH','VT','MA','RI','CT','NJ','DE','MD','DC'];\n    var px=808,py=308,pw=152,ph=neList.length*24+28;\n    var pb=document.createElementNS(ns,'rect');\n    pb.setAttribute('x',px);pb.setAttribute('y',py);pb.setAttribute('width',pw);pb.setAttribute('height',ph);\n    pb.setAttribute('fill','rgba(255,255,255,0.94)');pb.setAttribute('rx','5');pb.setAttribute('stroke','#bbb');pb.setAttribute('stroke-width','0.7');\n    svg.appendChild(pb);\n    var ptx=document.createElementNS(ns,'text');\n    ptx.setAttribute('x',px+pw\/2);ptx.setAttribute('y',py+17);\n    ptx.setAttribute('text-anchor','middle');ptx.setAttribute('font-size','13');\n    ptx.setAttribute('font-family','\"Courier New\",monospace');ptx.setAttribute('font-weight','700');ptx.setAttribute('fill','#444');\n    ptx.textContent='Northeast';svg.appendChild(ptx);\n    neList.forEach(function(abbr,i){\n      var d=tipYoYData[abbr];\n      var ry=py+31+i*24;\n      var sw=document.createElementNS(ns,'rect');\n      sw.setAttribute('x',px+7);sw.setAttribute('y',ry-7);sw.setAttribute('width','13');sw.setAttribute('height','13');\n      sw.setAttribute('fill',d!=null?tipColor(d):'#d8dbd6');sw.setAttribute('rx','2');svg.appendChild(sw);\n      var at=document.createElementNS(ns,'text');\n      at.setAttribute('x',px+26);at.setAttribute('y',ry+2);\n      at.setAttribute('font-size','13');at.setAttribute('font-family','\"Courier New\",monospace');\n      at.setAttribute('font-weight','700');at.setAttribute('fill','#111');\n      at.textContent=abbr;svg.appendChild(at);\n      if(d!=null){\n        var vt=document.createElementNS(ns,'text');\n        vt.setAttribute('x',px+pw-7);vt.setAttribute('y',ry+2);\n        vt.setAttribute('text-anchor','end');vt.setAttribute('font-size','13');\n        vt.setAttribute('font-family','\"Courier New\",monospace');vt.setAttribute('fill','#333');\n        vt.textContent=tipLabel(d);svg.appendChild(vt);\n      }\n      if(smallC[abbr]){\n        var dot=document.createElementNS(ns,'circle');\n        dot.setAttribute('cx',smallC[abbr][0]);dot.setAttribute('cy',smallC[abbr][1]);\n        dot.setAttribute('r','3');dot.setAttribute('fill',d!=null?tipColor(d):'#d8dbd6');\n        dot.setAttribute('stroke','#fff');dot.setAttribute('stroke-width','1');\n        dot.setAttribute('pointer-events','none');svg.appendChild(dot);\n      }\n    });\n    el.appendChild(svg);\n  });\n})();\n\n<\/script> <\/body> <\/html> \t\t\t\t<\/div> \t\t\t\t<\/div> \t\t\t\t\t<\/div> \t\t<\/div> \t\t\t\t\t<\/div> \t\t<\/section> \t\t\t\t<\/div>","protected":false},"excerpt":{"rendered":"<p>The State of Lawn Care in America: 2025 \u2014 LawnStarter LawnStarter Internal Data &bull; Full Year 2025 The State of [&hellip;]<\/p>\n","protected":false},"author":82,"featured_media":0,"parent":41374,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_header_footer","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-132866","page","type-page","status-publish","hentry"],"acf":[],"featured_image_src":null,"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>LawnStarter Industry Report - Lawnstarter<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lawnstarter.com\/blog\/statistics\/lawnstarter-industry-report\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"LawnStarter Industry Report - Lawnstarter\" \/>\n<meta property=\"og:description\" content=\"The State of Lawn Care in America: 2025 \u2014 LawnStarter LawnStarter Internal Data &bull; Full Year 2025 The State of [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lawnstarter.com\/blog\/statistics\/lawnstarter-industry-report\/\" \/>\n<meta property=\"og:site_name\" content=\"Lawnstarter\" \/>\n<meta property=\"article:modified_time\" content=\"2026-05-06T13:13:21+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"16 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/statistics\\\/lawnstarter-industry-report\\\/\",\"url\":\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/statistics\\\/lawnstarter-industry-report\\\/\",\"name\":\"LawnStarter Industry Report - Lawnstarter\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/#website\"},\"datePublished\":\"2025-05-01T02:19:23+00:00\",\"dateModified\":\"2026-05-06T13:13:21+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/statistics\\\/lawnstarter-industry-report\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/statistics\\\/lawnstarter-industry-report\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/statistics\\\/lawnstarter-industry-report\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Statistics\",\"item\":\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/statistics\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"LawnStarter Industry Report\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/\",\"name\":\"Lawnstarter\",\"description\":\"The LawnStarter Blog\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/#organization\",\"name\":\"Lawnstarter\",\"url\":\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/wp-content\\\/uploads\\\/2021\\\/10\\\/lawnstarter-logo.svg?wsr\",\"contentUrl\":\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/wp-content\\\/uploads\\\/2021\\\/10\\\/lawnstarter-logo.svg?wsr\",\"width\":198,\"height\":26,\"caption\":\"Lawnstarter\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lawnstarter.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"LawnStarter Industry Report - Lawnstarter","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lawnstarter.com\/blog\/statistics\/lawnstarter-industry-report\/","og_locale":"en_US","og_type":"article","og_title":"LawnStarter Industry Report - Lawnstarter","og_description":"The State of Lawn Care in America: 2025 \u2014 LawnStarter LawnStarter Internal Data &bull; Full Year 2025 The State of [&hellip;]","og_url":"https:\/\/www.lawnstarter.com\/blog\/statistics\/lawnstarter-industry-report\/","og_site_name":"Lawnstarter","article_modified_time":"2026-05-06T13:13:21+00:00","twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"16 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.lawnstarter.com\/blog\/statistics\/lawnstarter-industry-report\/","url":"https:\/\/www.lawnstarter.com\/blog\/statistics\/lawnstarter-industry-report\/","name":"LawnStarter Industry Report - Lawnstarter","isPartOf":{"@id":"https:\/\/www.lawnstarter.com\/blog\/#website"},"datePublished":"2025-05-01T02:19:23+00:00","dateModified":"2026-05-06T13:13:21+00:00","breadcrumb":{"@id":"https:\/\/www.lawnstarter.com\/blog\/statistics\/lawnstarter-industry-report\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lawnstarter.com\/blog\/statistics\/lawnstarter-industry-report\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lawnstarter.com\/blog\/statistics\/lawnstarter-industry-report\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lawnstarter.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Statistics","item":"https:\/\/www.lawnstarter.com\/blog\/statistics\/"},{"@type":"ListItem","position":3,"name":"LawnStarter Industry Report"}]},{"@type":"WebSite","@id":"https:\/\/www.lawnstarter.com\/blog\/#website","url":"https:\/\/www.lawnstarter.com\/blog\/","name":"Lawnstarter","description":"The LawnStarter Blog","publisher":{"@id":"https:\/\/www.lawnstarter.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lawnstarter.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.lawnstarter.com\/blog\/#organization","name":"Lawnstarter","url":"https:\/\/www.lawnstarter.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lawnstarter.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.lawnstarter.com\/blog\/wp-content\/uploads\/2021\/10\/lawnstarter-logo.svg?wsr","contentUrl":"https:\/\/www.lawnstarter.com\/blog\/wp-content\/uploads\/2021\/10\/lawnstarter-logo.svg?wsr","width":198,"height":26,"caption":"Lawnstarter"},"image":{"@id":"https:\/\/www.lawnstarter.com\/blog\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/www.lawnstarter.com\/blog\/wp-json\/wp\/v2\/pages\/132866","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lawnstarter.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.lawnstarter.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.lawnstarter.com\/blog\/wp-json\/wp\/v2\/users\/82"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lawnstarter.com\/blog\/wp-json\/wp\/v2\/comments?post=132866"}],"version-history":[{"count":27,"href":"https:\/\/www.lawnstarter.com\/blog\/wp-json\/wp\/v2\/pages\/132866\/revisions"}],"predecessor-version":[{"id":148849,"href":"https:\/\/www.lawnstarter.com\/blog\/wp-json\/wp\/v2\/pages\/132866\/revisions\/148849"}],"up":[{"embeddable":true,"href":"https:\/\/www.lawnstarter.com\/blog\/wp-json\/wp\/v2\/pages\/41374"}],"wp:attachment":[{"href":"https:\/\/www.lawnstarter.com\/blog\/wp-json\/wp\/v2\/media?parent=132866"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}