Mistral Mistral Large 4 – Pets

via Mistral · Generated

  • AIMAC Debt 7.05
  • Cost $0.36
  • Total Violations 7
  • HTML Size 88 KB
  • Em Dashes 92

Screenshot

View Mistral Mistral Large 4 Pets page View Live Page

Accessibility Issues Found

7 Serious

  • aria-prohibited-attr serious 4 instances

    Elements must only use permitted ARIA attributes

    Example HTML <span class="stars" aria-label="Rated 4.9 out of 5">
  • color-contrast serious 3 instances

    Elements must meet minimum color contrast ratio thresholds

    Example HTML <a href="#book" class="btn btn-primary btn-sm nav-cta">Book Appointment</a>

Artifacts

View Generated HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PawHaven — Veterinary Care, Adoption &amp; Training in Portland, OR</title>
<meta name="description" content="PawHaven brings a full-service veterinary clinic, an ethical adoption center, and force-free training under one roof. Every pet deserves a healthy, happy life.">
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Ccircle cx='32' cy='32' r='30' fill='%230E5F57'/%3E%3Ctext x='32' y='43' font-family='Georgia' font-size='32' fill='white' text-anchor='middle'%3EP%3C/text%3E%3C/svg%3E">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,500..700;1,9..144,500..700&family=Nunito+Sans:wght@400;600;700;800&display=swap" rel="stylesheet">
<style>
:root{
  --ink:#1c2b27; --muted:#5f6f69;
  --teal:#0e5f57; --teal-dark:#0a4741; --teal-deep:#0b3a35;
  --teal-tint:#e6f1ee;
  --amber:#e9a23b; --amber-tint:#fbf1de;
  --coral:#d95f43; --coral-tint:#fceae4;
  --paper:#faf7f1; --card:#ffffff; --line:#e8e1d3;
  --shadow-sm:0 1px 2px rgba(28,43,39,.05),0 4px 14px rgba(28,43,39,.06);
  --shadow-md:0 2px 6px rgba(28,43,39,.06),0 16px 38px rgba(28,43,39,.11);
  --font-display:"Fraunces",Georgia,serif;
  --font-body:"Nunito Sans","Segoe UI",sans-serif;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;font-family:var(--font-body);background:var(--paper);color:var(--ink);font-size:16px;line-height:1.6;-webkit-font-smoothing:antialiased}
img{max-width:100%;display:block}
h1,h2,h3,h4,p,ul{margin:0;padding:0}
button,input,select{font-family:inherit}
a{color:var(--teal)}
::selection{background:var(--teal);color:#fff}
:focus-visible{outline:3px solid rgba(14,95,87,.45);outline-offset:2px;border-radius:6px}
[hidden]{display:none!important}
[id]{scroll-margin-top:92px}
.container{width:100%;max-width:1180px;margin:0 auto;padding:0 24px}
.skip{position:fixed;top:-60px;left:16px;z-index:300;background:var(--teal);color:#fff;padding:10px 18px;border-radius:10px;font-weight:800;text-decoration:none;transition:top .2s}
.skip:focus{top:12px}

/* ---------- Buttons & links ---------- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:9px;font-weight:800;font-size:.93rem;padding:13px 22px;border-radius:999px;border:1.5px solid transparent;cursor:pointer;text-decoration:none;line-height:1;white-space:nowrap;transition:.2s}
.btn svg{width:17px;height:17px}
.btn-primary{background:var(--teal);color:#fff}
.btn-primary:hover{background:var(--teal-dark);transform:translateY(-1px);box-shadow:0 8px 20px rgba(14,95,87,.28)}
.btn-ghost{background:transparent;border-color:var(--line);color:var(--ink)}
.btn-ghost:hover{border-color:var(--teal);color:var(--teal)}
.btn-amber{background:var(--amber);color:#231a08}
.btn-amber:hover{background:#f0b254;transform:translateY(-1px);box-shadow:0 8px 20px rgba(233,162,59,.35)}
.btn-outline-light{background:transparent;border-color:rgba(255,255,255,.4);color:#fff}
.btn-outline-light:hover{background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.75)}
.btn-sm{padding:10px 18px;font-size:.86rem}
.btn-lg{padding:15px 26px;font-size:1rem}
.btn-block{width:100%}
.text-link{display:inline-flex;align-items:center;gap:7px;color:var(--teal);font-weight:800;font-size:.9rem;text-decoration:none}
.text-link svg{width:15px;height:15px;transition:transform .2s}
.text-link:hover svg{transform:translateX(4px)}
.stars{display:inline-flex;gap:2px}
.stars svg{width:15px;height:15px;fill:var(--amber);color:var(--amber)}

/* ---------- Section headers ---------- */
.section{padding:92px 0}
.section-alt{background:#fff}
.section-book{background:#eef4f1}
.eyebrow{display:inline-flex;align-items:center;gap:10px;font-size:.78rem;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--teal);margin-bottom:14px}
.eyebrow::before{content:"";width:22px;height:2px;background:var(--amber);border-radius:2px}
.section-head{display:flex;justify-content:space-between;align-items:flex-end;gap:40px;margin-bottom:44px}
.section-head h2{font-family:var(--font-display);font-weight:600;font-size:clamp(1.85rem,3.2vw,2.5rem);line-height:1.12;letter-spacing:-.01em}
.section-lead{max-width:470px;color:var(--muted);font-size:1rem;line-height:1.7}
.section-lead a{color:var(--teal);font-weight:800;text-decoration:none;border-bottom:1.5px solid rgba(14,95,87,.3)}
.section-head.center{flex-direction:column;align-items:center;text-align:center}
.section-head.center .section-lead{max-width:640px}
@media(max-width:900px){.section-head{flex-direction:column;align-items:flex-start;gap:16px}.section-head.center{align-items:center}}

/* ---------- Topbar ---------- */
.topbar{background:var(--teal-deep);color:rgba(255,255,255,.85);font-size:.82rem;font-weight:600}
.topbar-inner{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:9px 24px}
.topbar-tag{display:flex;align-items:center;gap:8px}
.topbar-tag svg{width:13px;height:13px;color:var(--amber)}
.topbar-info{display:flex;align-items:center;gap:16px}
.topbar-info span,.topbar-info a{display:flex;align-items:center;gap:7px;color:rgba(255,255,255,.75);text-decoration:none}
.topbar-info a:hover{color:#fff}
.topbar-info svg{width:13px;height:13px;color:#8fd0c2}
.topbar-divider{width:1px;height:14px;background:rgba(255,255,255,.2)}
@media(max-width:720px){.topbar-tag{display:none}.topbar-inner{justify-content:center}}

/* ---------- Header ---------- */
.site-header{position:sticky;top:0;z-index:100;background:rgba(250,247,241,.9);backdrop-filter:blur(10px);border-bottom:1px solid transparent;transition:.25s}
.site-header.scrolled{border-bottom-color:var(--line);box-shadow:0 6px 24px rgba(28,43,39,.07)}
.header-inner{display:flex;align-items:center;justify-content:space-between;height:76px;position:relative}
.brand img{height:46px;width:auto;border-radius:10px}
.main-nav{display:flex;align-items:center;gap:26px}
.main-nav>a{position:relative;color:var(--ink);text-decoration:none;font-weight:700;font-size:.93rem;padding:6px 0}
.main-nav>a:not(.nav-cta)::after{content:"";position:absolute;left:0;bottom:0;width:100%;height:2px;background:var(--teal);transform:scaleX(0);transform-origin:left;transition:transform .22s}
.main-nav>a:not(.nav-cta):hover{color:var(--teal)}
.main-nav>a:not(.nav-cta):hover::after{transform:scaleX(1)}
.menu-toggle{display:none}
@media(max-width:1120px){.main-nav{gap:18px}}
@media(max-width:960px){
  .menu-toggle{display:grid;place-items:center;width:44px;height:44px;border-radius:12px;border:1.5px solid var(--line);background:#fff;color:var(--ink);cursor:pointer}
  .menu-toggle svg{width:20px;height:20px}
  .menu-toggle .ic-close{display:none}
  .menu-toggle.open .ic-open{display:none}
  .menu-toggle.open .ic-close{display:block}
  .main-nav{display:none;position:absolute;top:calc(100% + 1px);left:0;right:0;background:#fff;flex-direction:column;align-items:stretch;gap:2px;padding:14px 24px 22px;border-bottom:1px solid var(--line);box-shadow:0 24px 40px rgba(28,43,39,.12)}
  .main-nav.open{display:flex}
  .main-nav>a{padding:13px 2px;font-size:1rem;border-bottom:1px solid var(--line)}
  .main-nav>a:not(.nav-cta)::after{display:none}
  .nav-cta{margin-top:14px;justify-content:center}
}

/* ---------- Hero ---------- */
.hero{padding:76px 0 132px;position:relative;overflow:hidden}
.hero::before{content:"";position:absolute;top:-180px;right:-120px;width:560px;height:560px;border-radius:50%;background:radial-gradient(closest-side,rgba(14,95,87,.09),transparent 72%);pointer-events:none}
.hero-inner{display:grid;grid-template-columns:1.05fr .95fr;gap:64px;align-items:center}
.hero h1{font-family:var(--font-display);font-weight:600;font-size:clamp(2.35rem,4.4vw,3.4rem);line-height:1.07;letter-spacing:-.015em;margin-bottom:22px}
.hero h1 em{font-style:italic;color:var(--teal)}
.hero .lead{font-size:1.1rem;color:var(--muted);line-height:1.7;max-width:520px;margin-bottom:30px}
.hero-actions{display:flex;gap:14px;flex-wrap:wrap;margin-bottom:30px}
.hero-trust{display:flex;align-items:center;gap:14px;flex-wrap:wrap;font-size:.87rem;color:var(--muted)}
.hero-trust strong{color:var(--ink)}
.trust-item{display:flex;align-items:center;gap:7px}
.trust-item svg{width:15px;height:15px;color:var(--teal)}
.trust-sep{width:1px;height:16px;background:var(--line)}
.hero-media{position:relative}
.hero-media>img{position:relative;z-index:1;width:100%;aspect-ratio:5/4;object-fit:cover;border-radius:28px;box-shadow:var(--shadow-md)}
.hero-media::before{content:"";position:absolute;inset:0;transform:translate(20px,20px);background:var(--teal-tint);border-radius:32px}
.hero-media::after{content:"";position:absolute;left:-26px;bottom:-26px;width:150px;height:110px;background-image:radial-gradient(rgba(14,95,87,.35) 1.5px,transparent 1.6px);background-size:15px 15px}
.float-chip{position:absolute;z-index:2;top:22px;left:-26px;background:#fff;border-radius:16px;box-shadow:var(--shadow-md);padding:12px 16px;display:flex;align-items:center;gap:11px;animation:floatY 5.5s ease-in-out infinite}
.float-ic{width:38px;height:38px;border-radius:11px;background:var(--teal-tint);color:var(--teal);display:grid;place-items:center}
.float-ic svg{width:18px;height:18px}
.float-chip small{display:block;font-size:.68rem;font-weight:800;letter-spacing:.09em;text-transform:uppercase;color:var(--muted)}
.float-chip strong{font-size:.92rem}
.float-card{position:absolute;z-index:2;bottom:-24px;right:-14px;background:#fff;border-radius:16px;box-shadow:var(--shadow-md);padding:12px 16px 12px 12px;display:flex;align-items:center;gap:11px}
.float-card img{width:44px;height:44px;border-radius:11px;object-fit:cover}
.float-card strong{display:block;font-size:.9rem}
.float-card small{display:flex;align-items:center;gap:5px;font-size:.76rem;color:var(--muted);font-weight:700}
.float-card small svg{width:12px;height:12px;color:var(--coral);fill:var(--coral)}
@keyframes floatY{0%,100%{transform:translateY(0)}50%{transform:translateY(-7px)}}
@media(max-width:1024px){.hero{padding:56px 0 112px}.hero-inner{grid-template-columns:1fr;gap:56px}.hero-media{max-width:560px;margin:0 auto;width:100%}}
@media(max-width:640px){.float-chip{left:10px;top:14px}.float-card{right:8px}.hero-media::before{transform:translate(12px,12px)}}

/* ---------- Stats ---------- */
.stats-wrap{position:relative;z-index:5;margin-top:-72px;padding-bottom:8px}
.stats-card{background:#fff;border-radius:20px;box-shadow:var(--shadow-md);display:grid;grid-template-columns:repeat(4,1fr);padding:30px 18px}
.stat{display:flex;flex-direction:column;align-items:center;text-align:center;gap:5px;padding:6px 18px;border-left:1px solid var(--line)}
.stat:first-child{border-left:0}
.stat-num{font-family:var(--font-display);font-weight:600;font-size:2.15rem;color:var(--teal);line-height:1.1}
.stat-label{font-size:.86rem;color:var(--muted);font-weight:600;max-width:180px}
@media(max-width:820px){.stats-card{grid-template-columns:1fr 1fr;row-gap:26px}.stat:nth-child(3){border-left:0}}

/* ---------- Services ---------- */
.services-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:22px}
.service-card{background:#fff;border:1px solid var(--line);border-radius:18px;padding:28px 26px;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;transition:transform .22s,box-shadow .22s}
.service-card:hover{transform:translateY(-5px);box-shadow:var(--shadow-md)}
.service-ic{width:54px;height:54px;border-radius:15px;background:var(--teal-tint);color:var(--teal);display:grid;place-items:center;margin-bottom:20px;transition:.22s}
.service-ic svg{width:24px;height:24px}
.service-card:hover .service-ic{background:var(--teal);color:#fff}
.service-card h3{font-family:var(--font-display);font-weight:600;font-size:1.28rem;margin-bottom:10px}
.service-card p{color:var(--muted);font-size:.93rem;line-height:1.68;margin-bottom:18px;flex:1}
@media(max-width:1080px){.services-grid{grid-template-columns:1fr 1fr}}
@media(max-width:600px){.services-grid{grid-template-columns:1fr}}

/* ---------- Booking ---------- */
.book-widget{background:#fff;border-radius:24px;box-shadow:var(--shadow-md);overflow:hidden}
.book-widget.flash{animation:flashPulse 1.6s ease}
@keyframes flashPulse{0%,100%{box-shadow:var(--shadow-md)}30%{box-shadow:0 0 0 7px rgba(233,162,59,.45),var(--shadow-md)}}
.book-widget.shake{animation:shake .5s}
@keyframes shake{10%,90%{transform:translateX(-1px)}20%,80%{transform:translateX(2px)}30%,50%,70%{transform:translateX(-4px)}40%,60%{transform:translateX(4px)}}
.book-grid{display:grid;grid-template-columns:1.12fr .88fr}
.book-form{padding:38px 40px}
.step{margin-bottom:30px}
.step-head{display:flex;align-items:center;gap:12px;margin-bottom:14px}
.step-num{width:28px;height:28px;border-radius:50%;background:var(--teal);color:#fff;font-size:.82rem;font-weight:800;display:grid;place-items:center;flex-shrink:0}
.step-head h3{font-size:1.02rem;font-weight:800}
.pill-row{display:flex;flex-wrap:wrap;gap:10px}
.pill{padding:10px 16px;border-radius:999px;border:1.5px solid var(--line);background:#fff;font-size:.9rem;font-weight:700;color:var(--ink);cursor:pointer;transition:.18s}
.pill span{opacity:.55;font-weight:400}
.pill:hover{border-color:var(--teal);color:var(--teal)}
.pill.selected{background:var(--teal);border-color:var(--teal);color:#fff}
.pill.selected span{opacity:.8}
.date-row{display:flex;gap:10px;overflow-x:auto;padding:2px 2px 10px;scroll-snap-type:x proximity;scrollbar-width:thin}
.date-row::-webkit-scrollbar{height:6px}
.date-row::-webkit-scrollbar-thumb{background:var(--line);border-radius:99px}
.date-chip{min-width:76px;padding:10px 8px;border-radius:14px;border:1.5px solid var(--line);background:#fff;display:flex;flex-direction:column;align-items:center;gap:2px;cursor:pointer;transition:.18s;scroll-snap-align:start}
.date-chip span{font-size:.68rem;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}
.date-chip strong{font-size:.86rem;font-weight:700}
.date-chip:hover:not(:disabled){border-color:var(--teal)}
.date-chip.selected{background:var(--teal);border-color:var(--teal)}
.date-chip.selected span{color:rgba(255,255,255,.75)}
.date-chip.selected strong{color:#fff}
.date-chip:disabled{background:transparent;border-style:dashed;cursor:not-allowed}
.date-chip:disabled span,.date-chip:disabled strong{color:#b9b2a4}
.time-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(92px,1fr));gap:10px}
.time-slot{padding:11px 6px;border-radius:11px;border:1.5px solid var(--line);background:#fff;font-size:.88rem;font-weight:700;color:var(--ink);cursor:pointer;transition:.15s}
.time-slot:hover:not(:disabled){border-color:var(--teal);color:var(--teal)}
.time-slot.selected{background:var(--teal);border-color:var(--teal);color:#fff}
.time-slot:disabled{border-style:dashed;color:#b9b2a4;text-decoration:line-through;cursor:not-allowed;background:#faf8f2}
.time-hint{grid-column:1/-1;color:var(--muted);font-size:.92rem;padding:6px 0}
.field-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.field{display:flex;flex-direction:column;gap:6px}
.field label{font-size:.8rem;font-weight:800;color:var(--muted)}
.field input,.field select{width:100%;padding:12px 14px;border-radius:12px;border:1.5px solid var(--line);font-size:.95rem;color:var(--ink);background:#fff;transition:.15s}
.field select{appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%235f6f69' stroke-width='2' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 14px center;padding-right:36px}
.field input:focus,.field select:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px rgba(14,95,87,.14)}
.invalid{border-color:var(--coral)!important;background:#fff6f3!important}
.book-error{display:flex;align-items:center;gap:9px;color:var(--coral);font-size:.9rem;font-weight:700;background:var(--coral-tint);border-radius:12px;padding:12px 16px;margin-bottom:16px}
.book-error svg{width:16px;height:16px;flex-shrink:0}
.book-note{font-size:.83rem;color:var(--muted);margin-top:14px;text-align:center}
.book-summary{background:#0b4a43;color:#fff;padding:38px 34px;display:flex;flex-direction:column}
.book-summary h3{font-family:var(--font-display);font-weight:600;font-size:1.35rem;margin-bottom:8px}
.sum-row{display:flex;justify-content:space-between;align-items:baseline;gap:16px;padding:13px 0;border-bottom:1px solid rgba(255,255,255,.14)}
.sum-row span{font-size:.72rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:rgba(255,255,255,.55)}
.sum-row strong{font-size:.98rem;text-align:right}
.sum-total{display:flex;justify-content:space-between;align-items:center;margin-top:18px;padding:16px 18px;border-radius:14px;background:rgba(255,255,255,.1)}
.sum-total strong{font-family:var(--font-display);font-size:1.35rem}
.sum-next{list-style:none;margin-top:22px;display:flex;flex-direction:column;gap:10px}
.sum-next li{display:flex;gap:10px;align-items:center;font-size:.88rem;color:rgba(255,255,255,.85)}
.sum-next svg{width:16px;height:16px;color:#8fd0c2;flex-shrink:0}
.book-success{padding:56px 32px;display:flex;justify-content:center}
.success-inner{max-width:520px;text-align:center;display:flex;flex-direction:column;align-items:center;gap:14px}
.check-svg{width:78px;height:78px}
.check-svg circle{fill:var(--teal-tint);stroke:var(--teal);stroke-width:2;stroke-dasharray:158;stroke-dashoffset:158;animation:draw .7s ease forwards}
.check-svg path{fill:none;stroke:var(--teal);stroke-width:3.5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:38;stroke-dashoffset:38;animation:draw .45s .55s ease forwards}
@keyframes draw{to{stroke-dashoffset:0}}
.success-inner h3{font-family:var(--font-display);font-weight:600;font-size:1.6rem}
.success-inner p{color:#42514c;line-height:1.7;font-size:.98rem}
.ref-chip{background:var(--teal-tint);color:var(--teal-dark);padding:9px 16px;border-radius:10px;font-size:.9rem;font-weight:700}
.ref-chip strong{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.04em}
.success-small{font-size:.85rem;color:var(--muted)}
.success-actions{display:flex;gap:12px;flex-wrap:wrap;justify-content:center;margin-top:6px}
@media(max-width:980px){.book-grid{grid-template-columns:1fr}.book-form{padding:28px 22px}.book-summary{padding:28px 22px}}
@media(max-width:560px){.field-grid{grid-template-columns:1fr}.book-success{padding:40px 20px}}

/* ---------- Journal / posts ---------- */
.tabs{display:flex;gap:9px;flex-wrap:wrap;margin-bottom:34px}
.tab{padding:10px 18px;border-radius:999px;border:1.5px solid var(--line);background:#fff;font-size:.88rem;font-weight:800;color:var(--muted);cursor:pointer;transition:.18s}
.tab:hover{border-color:var(--teal);color:var(--teal)}
.tab.active{background:var(--teal);border-color:var(--teal);color:#fff}
.posts-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}
.post-card{background:#fff;border:1px solid var(--line);border-radius:18px;overflow:hidden;cursor:pointer;box-shadow:var(--shadow-sm);transition:transform .22s,box-shadow .22s;animation:cardIn .5s ease backwards}
.post-card:hover{transform:translateY(-5px);box-shadow:var(--shadow-md)}
.post-card:focus-visible{outline:3px solid rgba(14,95,87,.45);outline-offset:2px}
.post-media{position:relative;aspect-ratio:16/10;overflow:hidden}
.post-media img{width:100%;height:100%;object-fit:cover;transition:transform .5s}
.post-card:hover .post-media img{transform:scale(1.05)}
.post-chip{position:absolute;top:12px;left:12px;background:rgba(255,255,255,.94);color:var(--teal);font-size:.7rem;font-weight:800;letter-spacing:.08em;text-transform:uppercase;padding:6px 12px;border-radius:999px}
.post-chip.static{position:static;background:var(--teal-tint)}
.post-body{padding:22px 22px 24px}
.post-meta{display:flex;align-items:center;gap:8px;font-size:.8rem;font-weight:700;color:var(--muted);margin-bottom:10px}
.post-meta svg{width:13px;height:13px}
.dot{width:3px;height:3px;border-radius:50%;background:#c9c2b2}
.post-body h3{font-family:var(--font-display);font-weight:600;font-size:1.18rem;line-height:1.32;margin-bottom:10px}
.post-body>p{color:var(--muted);font-size:.9rem;line-height:1.65;margin-bottom:16px}
@keyframes cardIn{from{opacity:0;transform:translateY(18px)}to{opacity:1;transform:none}}
.library-more{display:flex;justify-content:center;margin-top:42px}
@media(max-width:1024px){.posts-grid{grid-template-columns:1fr 1fr}}
@media(max-width:640px){.posts-grid{grid-template-columns:1fr}}

/* ---------- Adoption ---------- */
.adoption-grid{display:grid;grid-template-columns:1.55fr 1fr;gap:56px;align-items:start}
.stories{display:flex;flex-direction:column;gap:18px;margin-top:6px}
.story-card{display:flex;gap:22px;background:var(--paper);border:1px solid var(--line);border-radius:18px;padding:20px;box-shadow:var(--shadow-sm)}
.story-card img{width:190px;height:150px;object-fit:cover;border-radius:14px;flex-shrink:0}
.story-quote{width:22px;height:22px;color:var(--amber);margin-bottom:8px}
.story-body>p{font-size:1rem;color:#3d4c47;line-height:1.65;margin-bottom:14px}
.story-foot{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.story-meta{font-size:.85rem;color:var(--muted)}
.adoption-cta{margin-top:26px;background:var(--teal-tint);border-radius:18px;padding:26px 28px;display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap}
.adoption-cta h3{font-family:var(--font-display);font-weight:600;font-size:1.25rem;margin-bottom:6px}
.adoption-cta p{color:var(--muted);font-size:.93rem;max-width:430px;line-height:1.6}
.adoption-side{display:flex;flex-direction:column;gap:22px}
.side-card{background:#fff;border:1px solid var(--line);border-radius:18px;padding:24px;box-shadow:var(--shadow-sm)}
.side-head{display:flex;align-items:center;gap:10px;margin-bottom:14px}
.side-head svg{width:20px;height:20px;color:var(--teal)}
.side-head h3{font-family:var(--font-display);font-weight:600;font-size:1.15rem}
.event-list{list-style:none}
.event{display:flex;align-items:center;gap:14px;padding:13px 0;border-top:1px solid var(--line)}
.event:first-child{border-top:0;padding-top:2px}
.event-date{width:52px;height:56px;border-radius:12px;background:var(--teal-tint);color:var(--teal);display:flex;flex-direction:column;align-items:center;justify-content:center;flex-shrink:0}
.event-date span{font-size:.62rem;font-weight:800;letter-spacing:.1em}
.event-date strong{font-family:var(--font-display);font-size:1.25rem;line-height:1.1}
.event-info{flex:1;min-width:0}
.event-info strong{display:block;font-size:.93rem}
.event-info span{font-size:.8rem;color:var(--muted)}
.event-ics{width:34px;height:34px;border-radius:10px;border:1.5px solid var(--line);background:#fff;color:var(--muted);display:grid;place-items:center;cursor:pointer;transition:.15s;flex-shrink:0}
.event-ics:hover{border-color:var(--teal);color:var(--teal)}
.event-ics svg{width:15px;height:15px}
.pet-list{list-style:none}
.pet-row{display:flex;align-items:center;gap:12px;padding:11px 0;border-top:1px solid var(--line)}
.pet-row:first-child{border-top:0;padding-top:2px}
.pet-row img{width:52px;height:52px;border-radius:12px;object-fit:cover}
.pet-row strong{display:block;font-size:.95rem}
.pet-row div span{font-size:.8rem;color:var(--muted)}
.pet-meet{margin-left:auto;padding:7px 14px;border-radius:999px;border:1.5px solid var(--teal);background:transparent;color:var(--teal);font-size:.82rem;font-weight:800;cursor:pointer;transition:.15s}
.pet-meet:hover{background:var(--teal);color:#fff}
.side-news{background:var(--teal-tint);border-color:rgba(14,95,87,.18)}
.side-news>p{font-size:.9rem;color:#3d4c47;margin-bottom:14px;line-height:1.6}
#newsForm{display:flex;gap:10px}
#newsForm input{flex:1;min-width:0;padding:12px 14px;border-radius:12px;border:1.5px solid rgba(14,95,87,.25);font-size:.92rem;background:#fff}
#newsForm input:focus{outline:none;border-color:var(--teal);box-shadow:0 0 0 3px rgba(14,95,87,.15)}
#newsForm button{padding:0 16px;border-radius:12px}
.news-error{color:var(--coral);font-size:.82rem;font-weight:700;margin-top:8px}
.news-done{display:flex;align-items:center;gap:8px;font-weight:800;color:var(--teal);font-size:.95rem}
.news-done svg{width:18px;height:18px}
@media(max-width:1024px){.adoption-grid{grid-template-columns:1fr}.adoption-side{display:grid;grid-template-columns:1fr 1fr;align-items:start}}
@media(max-width:680px){.adoption-side{grid-template-columns:1fr}.story-card{flex-direction:column}.story-card img{width:100%;height:190px}}

/* ---------- FAQ ---------- */
.faq-wrap{max-width:800px}
.faq-list{display:flex;flex-direction:column;gap:12px;margin-top:38px}
.faq-item{background:#fff;border:1px solid var(--line);border-radius:16px;overflow:hidden;transition:box-shadow .2s}
.faq-item.open{box-shadow:var(--shadow-md)}
.faq-q{width:100%;display:flex;justify-content:space-between;align-items:center;gap:18px;padding:19px 22px;background:none;border:0;font-size:1.02rem;font-weight:800;color:var(--ink);text-align:left;cursor:pointer}
.faq-ic{width:30px;height:30px;border-radius:50%;background:var(--teal-tint);color:var(--teal);display:grid;place-items:center;flex-shrink:0;transition:transform .3s,background .3s,color .3s}
.faq-ic svg{width:16px;height:16px}
.faq-item.open .faq-ic{transform:rotate(45deg);background:var(--teal);color:#fff}
.faq-a{display:grid;grid-template-rows:0fr;transition:grid-template-rows .35s ease}
.faq-item.open .faq-a{grid-template-rows:1fr}
.faq-a-inner{overflow:hidden}
.faq-a-inner p{padding:0 22px 20px;color:var(--muted);font-size:.95rem;line-height:1.7}

/* ---------- CTA banner ---------- */
.cta-wrap{padding:10px 0 96px}
.cta-banner{position:relative;overflow:hidden;background:var(--teal-deep);border-radius:28px;padding:64px 56px;color:#fff}
.cta-banner h2{font-family:var(--font-display);font-weight:600;font-size:clamp(1.7rem,3vw,2.3rem);line-height:1.15;max-width:560px;margin-bottom:14px}
.cta-banner>p{color:rgba(255,255,255,.75);max-width:520px;font-size:1.02rem;line-height:1.65;margin-bottom:28px}
.cta-paw{position:absolute;color:#fff;opacity:.06;pointer-events:none}
.cta-paw-1{width:230px;height:230px;top:-60px;right:-40px;transform:rotate(24deg)}
.cta-paw-2{width:160px;height:160px;bottom:-50px;left:34%;transform:rotate(-18deg)}
.cta-actions{display:flex;gap:14px;flex-wrap:wrap;position:relative}
.cta-call{margin-top:22px;font-size:.88rem;color:rgba(255,255,255,.6);display:flex;align-items:center;gap:8px}
.cta-call svg{width:15px;height:15px}
@media(max-width:640px){.cta-banner{padding:44px 26px}}

/* ---------- Footer ---------- */
.site-footer{background:#14211e;color:rgba(255,255,255,.72)}
.footer-grid{display:grid;grid-template-columns:1.6fr 1fr 1fr 1.3fr;gap:48px;padding:72px 0 0}
.footer-brand img{border-radius:10px;margin-bottom:18px}
.footer-brand p{font-size:.93rem;line-height:1.7;max-width:300px;margin-bottom:20px}
.socials{display:flex;gap:10px}
.socials a{width:38px;height:38px;border-radius:50%;border:1px solid rgba(255,255,255,.18);display:grid;place-items:center;color:rgba(255,255,255,.75);transition:.18s}
.socials a:hover{background:var(--amber);border-color:var(--amber);color:#1c2b27;transform:translateY(-2px)}
.socials svg{width:17px;height:17px}
.footer-col h4{color:#fff;font-size:.8rem;font-weight:800;letter-spacing:.14em;text-transform:uppercase;margin-bottom:18px}
.footer-col a{display:block;color:rgba(255,255,255,.62);text-decoration:none;font-size:.93rem;padding:5px 0;transition:.15s}
.footer-col a:hover{color:#fff;padding-left:4px}
.footer-contact p{display:flex;gap:10px;font-size:.92rem;padding:5px 0;line-height:1.55}
.footer-contact svg{width:16px;height:16px;color:#7fc4b8;flex-shrink:0;margin-top:4px}
.footer-contact a{color:rgba(255,255,255,.72);text-decoration:none}
.footer-contact a:hover{color:#fff}
.footer-bottom{display:flex;justify-content:space-between;align-items:center;gap:16px;flex-wrap:wrap;border-top:1px solid rgba(255,255,255,.1);margin-top:56px;padding:22px 0 26px;font-size:.85rem;color:rgba(255,255,255,.45)}
.footer-legal{display:flex;gap:22px}
.footer-legal a{color:rgba(255,255,255,.55);text-decoration:none}
.footer-legal a:hover{color:#fff}
@media(max-width:960px){.footer-grid{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.footer-grid{grid-template-columns:1fr;gap:36px}}

/* ---------- Modal ---------- */
.modal-overlay{position:fixed;inset:0;background:rgba(16,26,23,.55);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;padding:22px;z-index:120;opacity:0;pointer-events:none;transition:opacity .25s}
.modal-overlay.open{opacity:1;pointer-events:auto}
.modal-panel{position:relative;background:#fff;border-radius:22px;max-width:680px;width:100%;max-height:86vh;overflow-y:auto;box-shadow:0 30px 80px rgba(16,26,23,.35);transform:translateY(16px) scale(.98);transition:transform .3s}
.modal-overlay.open .modal-panel{transform:none}
.modal-close{position:sticky;top:14px;z-index:5;margin:14px 14px -52px auto;width:38px;height:38px;border-radius:50%;border:0;background:rgba(255,255,255,.94);color:var(--ink);display:grid;place-items:center;cursor:pointer;box-shadow:var(--shadow-md)}
.modal-close svg{width:18px;height:18px}
.modal-img{width:100%;aspect-ratio:16/8.5;object-fit:cover}
.modal-pad{padding:30px 34px 34px}
.modal-meta{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:14px}
.modal-meta-text{font-size:.85rem;color:var(--muted);font-weight:600}
.modal-title{font-family:var(--font-display);font-weight:600;font-size:1.55rem;line-height:1.25;margin-bottom:16px}
.modal-pad p{color:#42514c;font-size:.98rem;line-height:1.75;margin-bottom:14px}
.modal-foot{display:flex;gap:12px;flex-wrap:wrap;margin-top:22px}
.pet-head{display:flex;gap:20px;align-items:center;margin-bottom:18px;flex-wrap:wrap}
.pet-head img{width:96px;height:96px;border-radius:18px;object-fit:cover}
.pet-sub{margin:4px 0 10px;color:var(--muted);font-size:.92rem;font-weight:600}
.pet-tags{display:flex;gap:8px;flex-wrap:wrap}
.pet-tags span{background:var(--teal-tint);color:var(--teal);font-size:.75rem;font-weight:800;padding:5px 11px;border-radius:999px}
.pet-good{font-size:.93rem}
@media(max-width:560px){.modal-pad{padding:24px 22px 28px}}

/* ---------- Toast & to-top ---------- */
.toast{position:fixed;bottom:26px;left:50%;transform:translate(-50%,16px);background:#1c2b27;color:#fff;padding:13px 20px;border-radius:999px;display:flex;align-items:center;gap:10px;font-size:.92rem;font-weight:600;box-shadow:0 12px 32px rgba(16,26,23,.35);z-index:150;opacity:0;pointer-events:none;transition:.3s;max-width:calc(100vw - 40px)}
.toast.show{opacity:1;transform:translate(-50%,0)}
.toast svg{width:17px;height:17px;color:#8fd0c2;flex-shrink:0}
.to-top{position:fixed;bottom:26px;right:26px;width:46px;height:46px;border-radius:50%;border:0;background:var(--teal);color:#fff;display:grid;place-items:center;cursor:pointer;box-shadow:var(--shadow-md);z-index:110;opacity:0;pointer-events:none;transform:translateY(10px);transition:.25s}
.to-top.show{opacity:1;pointer-events:auto;transform:none}
.to-top:hover{background:var(--teal-dark)}
.to-top svg{width:19px;height:19px}

/* ---------- Reveal ---------- */
.reveal{opacity:0}
.reveal.in{animation:rise .65s cubic-bezier(.22,.61,.36,1) both}
.reveal.done{opacity:1}
@keyframes rise{from{opacity:0;transform:translateY(24px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .reveal{opacity:1}.reveal.in{animation:none}
  .float-chip{animation:none}
  .check-svg circle,.check-svg path{animation:none;stroke-dashoffset:0}
  .post-card{animation:none}
}
</style>
</head>
<body>
<a class="skip" href="#main">Skip to content</a>

<!-- Topbar -->
<div class="topbar">
  <div class="container topbar-inner">
    <p class="topbar-tag"><i data-lucide="heart"></i>Every pet deserves a healthy, happy life.</p>
    <div class="topbar-info">
      <span><i data-lucide="clock"></i>Mon–Fri 8–7 · Sat 9–5</span>
      <span class="topbar-divider"></span>
      <a href="tel:+15035550148"><i data-lucide="phone"></i>(503) 555-0148</a>
    </div>
  </div>
</div>

<!-- Header -->
<header class="site-header" id="siteHeader">
  <div class="container header-inner">
    <a href="#home" class="brand" aria-label="PawHaven — home">
      <img src="https://placehold.co/196x56/0E5F57/FFFFFF?text=PawHaven&amp;font=playfair+display" alt="PawHaven logo" width="196" height="56">
    </a>
    <nav class="main-nav" id="mainNav" aria-label="Primary">
      <a href="#home">Home</a>
      <a href="#services">Pet Care</a>
      <a href="#book">Book a Visit</a>
      <a href="#adoption">Adoption</a>
      <a href="#library">Blog</a>
      <a href="#faq">FAQ</a>
      <a href="#contact">Contact</a>
      <a href="#book" class="btn btn-primary btn-sm nav-cta">Book Appointment</a>
    </nav>
    <button class="menu-toggle" id="menuToggle" aria-expanded="false" aria-controls="mainNav" aria-label="Toggle menu">
      <i data-lucide="menu" class="ic-open"></i><i data-lucide="x" class="ic-close"></i>
    </button>
  </div>
</header>

<main id="main">
  <!-- Hero -->
  <section class="hero" id="home">
    <div class="container hero-inner">
      <div class="hero-copy reveal">
        <p class="eyebrow">Veterinary care · Adoption · Training — Portland, OR</p>
        <h1>Everything your pet needs for a <em>lifetime</em> of good health.</h1>
        <p class="lead">PawHaven brings a full-service veterinary clinic, an ethical adoption center, and force-free training under one roof — so your best friend gets consistent, compassionate care from their first puppy day to their golden years.</p>
        <div class="hero-actions">
          <a href="#book" class="btn btn-primary btn-lg">Book a Wellness Exam <i data-lucide="arrow-right"></i></a>
          <a href="#adoption" class="btn btn-ghost btn-lg">Meet Adoptable Pets</a>
        </div>
        <div class="hero-trust">
          <span class="stars" aria-label="Rated 4.9 out of 5"><i data-lucide="star"></i><i data-lucide="star"></i><i data-lucide="star"></i><i data-lucide="star"></i><i data-lucide="star"></i></span>
          <span><strong>4.9</strong> · 1,200+ reviews</span>
          <span class="trust-sep"></span>
          <span class="trust-item"><i data-lucide="shield-check"></i>Fear-Free® certified</span>
          <span class="trust-sep"></span>
          <span class="trust-item"><i data-lucide="badge-check"></i>AAHA-accredited</span>
        </div>
      </div>
      <div class="hero-media reveal" style="animation-delay:.12s">
        <img src="https://picsum.photos/seed/pawhaven-hero/900/720.jpg" alt="A happy dog with its owner at the PawHaven clinic" width="900" height="720">
        <div class="float-chip">
          <span class="float-ic"><i data-lucide="calendar-check"></i></span>
          <span><small>Next opening</small><strong id="nextOpen">Today · 2:45 PM</strong></span>
        </div>
        <div class="float-card">
          <img src="https://picsum.photos/seed/ph-maya/96/96.jpg" alt="Maya and Luna" width="96" height="96">
          <span><strong>Luna &amp; Maya</strong><small><i data-lucide="heart"></i>Adopted last week</small></span>
        </div>
      </div>
    </div>
  </section>

  <!-- Stats -->
  <section class="stats-wrap" aria-label="PawHaven by the numbers">
    <div class="container">
      <div class="stats-card reveal" id="statsCard">
        <div class="stat"><span class="stat-num" data-count="16">16</span><span class="stat-label">Years caring for Portland's pets</span></div>
        <div class="stat"><span class="stat-num" data-count="12400" data-suffix="+">12,400+</span><span class="stat-label">Patients treated &amp; counting</span></div>
        <div class="stat"><span class="stat-num" data-count="312">312</span><span class="stat-label">Adoptions placed in 2025</span></div>
        <div class="stat"><span class="stat-num" data-count="40" data-suffix="+">40+</span><span class="stat-label">Breed &amp; care guides published</span></div>
      </div>
    </div>
  </section>

  <!-- Services -->
  <section class="section" id="services">
    <div class="container">
      <div class="section-head reveal">
        <div>
          <p class="eyebrow">What we do</p>
          <h2>One team for every chapter of their life</h2>
        </div>
        <p class="section-lead">Whether you're booking a routine wellness exam, searching for a new family member, or working through a behavior challenge, our clinic, adoption center, and training studio share one philosophy: care that's evidence-based, fear-free, and built around the pet in front of us.</p>
      </div>
      <div class="services-grid stagger">
        <article class="service-card reveal">
          <span class="service-ic"><i data-lucide="stethoscope"></i></span>
          <h3>Veterinary Care</h3>
          <p>From annual wellness exams and vaccinations to dental care, diagnostics, and surgery, our AAHA-accredited clinic covers every stage of your pet's medical life — with same-day sick visits held every morning.</p>
          <a href="#book" class="text-link">Book a visit <i data-lucide="arrow-right"></i></a>
        </article>
        <article class="service-card reveal">
          <span class="service-ic"><i data-lucide="heart-handshake"></i></span>
          <h3>Adoption &amp; Rescue</h3>
          <p>We partner with 20+ local rescues and foster networks to place homeless dogs and cats into carefully matched homes. Every adoption includes a wellness exam, spay or neuter, microchipping, and a starter kit.</p>
          <a href="#adoption" class="text-link">Meet adoptable pets <i data-lucide="arrow-right"></i></a>
        </article>
        <article class="service-card reveal">
          <span class="service-ic"><i data-lucide="graduation-cap"></i></span>
          <h3>Training &amp; Behavior</h3>
          <p>Our certified trainers use positive, reward-based methods — from puppy socialization and leash manners to reactivity and behavior rehabilitation. Every adoption comes with free classes for life.</p>
          <a href="#library" class="text-link">See training programs <i data-lucide="arrow-right"></i></a>
        </article>
        <article class="service-card reveal">
          <span class="service-ic"><i data-lucide="scissors"></i></span>
          <h3>Grooming &amp; Wellness</h3>
          <p>Low-stress grooming and bathing, nutrition counseling, and life-stage wellness plans that evolve with your pet — from a playful kittenhood to dignified, comfortable senior years.</p>
          <a href="#book" class="text-link">Book grooming <i data-lucide="arrow-right"></i></a>
        </article>
      </div>
    </div>
  </section>

  <!-- Appointment scheduler -->
  <section class="section section-book" id="book">
    <div class="container">
      <div class="section-head center reveal">
        <div>
          <p class="eyebrow">Appointments</p>
          <h2>Book a visit in under a minute</h2>
        </div>
        <p class="section-lead">Choose a service, pick a time that fits your week, and we'll confirm by text — usually within 15 minutes during open hours. Same-day sick visits are held every morning; if your pet seems unwell, call <a href="tel:+15035550148">(503) 555-0148</a> right away.</p>
      </div>
      <div class="reveal">
        <div class="book-widget" id="bookWidget">
          <div class="book-grid" id="bookGrid">
            <form class="book-form" id="bookForm" novalidate>
              <div class="step">
                <div class="step-head"><span class="step-num">1</span><h3>What do you need?</h3></div>
                <div class="pill-row" id="servicePills"></div>
              </div>
              <div class="step">
                <div class="step-head"><span class="step-num">2</span><h3>Pick a day</h3></div>
                <div class="date-row" id="dateRow"></div>
              </div>
              <div class="step">
                <div class="step-head"><span class="step-num">3</span><h3>Pick a time</h3></div>
                <div class="time-grid" id="timeGrid"><p class="time-hint">Choose a day above to see open times.</p></div>
              </div>
              <div class="step">
                <div class="step-head"><span class="step-num">4</span><h3>Tell us about your pet</h3></div>
                <div class="field-grid">
                  <div class="field"><label for="petName">Pet's name</label><input id="petName" type="text" placeholder="e.g. Biscuit" autocomplete="off"></div>
                  <div class="field"><label for="petType">Pet type</label><select id="petType"><option>Dog</option><option>Cat</option><option>Rabbit</option><option>Bird</option><option>Other</option></select></div>
                  <div class="field"><label for="ownerName">Your name</label><input id="ownerName" type="text" placeholder="e.g. Maya Reyes" autocomplete="name"></div>
                  <div class="field"><label for="ownerPhone">Phone</label><input id="ownerPhone" type="tel" placeholder="(503) 555-0123" autocomplete="tel" inputmode="tel"></div>
                </div>
              </div>
              <p class="book-error" id="bookError" hidden><i data-lucide="info"></i>Please complete the highlighted fields — and pick a service, day, and time.</p>
              <button type="submit" class="btn btn-primary btn-lg btn-block">Request Appointment <i data-lucide="calendar-check"></i></button>
              <p class="book-note">No payment needed to book. Prices are starting estimates — your vet confirms costs before any procedure.</p>
            </form>
            <aside class="book-summary" aria-label="Appointment summary">
              <h3>Your appointment</h3>
              <div class="sum-row"><span>Service</span><strong id="sumService">—</strong></div>
              <div class="sum-row"><span>Day</span><strong id="sumDate">—</strong></div>
              <div class="sum-row"><span>Time</span><strong id="sumTime">—</strong></div>
              <div class="sum-row"><span>Pet</span><strong id="sumPet">—</strong></div>
              <div class="sum-row"><span>Owner</span><strong id="sumOwner">—</strong></div>
              <div class="sum-total"><span>Estimated total</span><strong id="sumPrice">—</strong></div>
              <ul class="sum-next">
                <li><i data-lucide="check"></i>We confirm by text within 15 minutes</li>
                <li><i data-lucide="check"></i>Arrive 10 minutes early for check-in</li>
                <li><i data-lucide="check"></i>Free rescheduling up to 12 hours before</li>
              </ul>
            </aside>
          </div>
          <div class="book-success" id="bookSuccess" hidden></div>
        </div>
      </div>
    </div>
  </section>

  <!-- Journal / Blog -->
  <section class="section" id="library">
    <div class="container">
      <div class="section-head reveal">
        <div>
          <p class="eyebrow">The PawHaven Journal</p>
          <h2>Expert guides for every kind of pet parent</h2>
        </div>
        <p class="section-lead">Written and reviewed by our veterinarians and certified trainers, the Journal turns real exam-room experience into practical, jargon-free reading — breed characteristics, life-stage care, behavior, and nutrition.</p>
      </div>
      <div class="tabs reveal" id="postTabs" role="tablist" aria-label="Filter guides by topic"></div>
      <div class="posts-grid" id="postsGrid"></div>
      <div class="library-more reveal">
        <button class="btn btn-ghost" id="browseAll">Browse all 40+ guides <i data-lucide="arrow-right"></i></button>
      </div>
    </div>
  </section>

  <!-- Adoption + sidebar -->
  <section class="section section-alt" id="adoption">
    <div class="container adoption-grid">
      <div class="adoption-main">
        <div class="section-head reveal">
          <div>
            <p class="eyebrow">Adoption &amp; rescue</p>
            <h2>Happy tails start here</h2>
          </div>
          <p class="section-lead">Every year our adoption center places hundreds of dogs and cats into loving homes — and every placement is only the beginning. We screen carefully, match thoughtfully, and stay involved long after the paperwork is signed, because the right fit matters more than a fast one.</p>
        </div>
        <div class="stories">
          <article class="story-card reveal">
            <img src="https://picsum.photos/seed/ph-luna/480/360.jpg" alt="Luna the cat curled up at home with her adopter" loading="lazy">
            <div class="story-body">
              <i data-lucide="quote" class="story-quote"></i>
              <p>"Luna hid behind the sofa for exactly four days. Then she decided we were hers. The team checked in every week for a month — that's the difference between a shelter and a rescue that actually rescues."</p>
              <div class="story-foot">
                <span class="stars" aria-label="5 out of 5 stars"><i data-lucide="star"></i><i data-lucide="star"></i><i data-lucide="star"></i><i data-lucide="star"></i><i data-lucide="star"></i></span>
                <span class="story-meta"><strong>Maya R.</strong> adopted Luna · Jan 2025</span>
              </div>
            </div>
          </article>
          <article class="story-card reveal">
            <img src="https://picsum.photos/seed/ph-barnaby/480/360.jpg" alt="Barnaby the dog out on a walk with his family" loading="lazy">
            <div class="story-body">
              <i data-lucide="quote" class="story-quote"></i>
              <p>"Barnaby had bounced between two homes before ours, so we were nervous. PawHaven's behavior team built us a training plan before we even brought him home — his reactivity around bikes went from daily meltdowns to a manageable quirk."</p>
              <div class="story-foot">
                <span class="stars" aria-label="5 out of 5 stars"><i data-lucide="star"></i><i data-lucide="star"></i><i data-lucide="star"></i><i data-lucide="star"></i><i data-lucide="star"></i></span>
                <span class="story-meta"><strong>The Okafor family</strong> adopted Barnaby · Mar 2025</span>
              </div>
            </div>
          </article>
          <article class="story-card reveal">
            <img src="https://picsum.photos/seed/ph-milo/480/360.jpg" alt="Milo the senior cat relaxing in a sunny window" loading="lazy">
            <div class="story-body">
              <i data-lucide="quote" class="story-quote"></i>
              <p>"At eleven, Milo was the least likely to be chosen. The adoption counselor walked us through senior cat care — the vet schedule, the costs, the little things like heated beds. Eight months later, he's the king of our living room."</p>
              <div class="story-foot">
                <span class="stars" aria-label="5 out of 5 stars"><i data-lucide="star"></i><i data-lucide="star"></i><i data-lucide="star"></i><i data-lucide="star"></i><i data-lucide="star"></i></span>
                <span class="story-meta"><strong>Jules P.</strong> adopted Milo · Nov 2024</span>
              </div>
            </div>
          </article>
        </div>
        <div class="adoption-cta reveal">
          <div>
            <h3>Ready to meet someone furry?</h3>
            <p>Adoption visits are free and pressure-free — come see who's waiting. No appointment needed on Saturday mornings.</p>
          </div>
          <button class="btn btn-primary" id="adoptCtaBtn">Start an Adoption Application <i data-lucide="arrow-right"></i></button>
        </div>
      </div>
      <aside class="adoption-side" aria-label="Adoption resources">
        <div class="side-card reveal">
          <div class="side-head"><i data-lucide="calendar-days"></i><h3>Adoption events</h3></div>
          <ul class="event-list">
            <li class="event">
              <div class="event-date"><span>JUN</span><strong>7</strong></div>
              <div class="event-info"><strong>Yappy Hour Meet &amp; Greet</strong><span>10:00–11:30 AM · Maplewood Patio</span></div>
              <button class="event-ics" data-title="Yappy Hour Meet &amp; Greet" data-loc="PawHaven — 742 Maplewood Avenue, Portland, OR" data-start="20250607T100000" data-end="20250607T113000" aria-label="Add Yappy Hour to calendar"><i data-lucide="download"></i></button>
            </li>
            <li class="event">
              <div class="event-date"><span>JUN</span><strong>14</strong></div>
              <div class="event-info"><strong>Cat Adoption Morning</strong><span>9:00–11:00 AM · The Cat Wing</span></div>
              <button class="event-ics" data-title="Cat Adoption Morning" data-loc="PawHaven — 742 Maplewood Avenue, Portland, OR" data-start="20250614T090000" data-end="20250614T110000" aria-label="Add Cat Adoption Morning to calendar"><i data-lucide="download"></i></button>
            </li>
            <li class="event">
              <div class="event-date"><span>JUN</span><strong>21</strong></div>
              <div class="event-info"><strong>New Foster Orientation</strong><span>1:00–2:30 PM · Training Studio</span></div>
              <button class="event-ics" data-title="New Foster Orientation" data-loc="PawHaven — 742 Maplewood Avenue, Portland, OR" data-start="20250621T130000" data-end="20250621T143000" aria-label="Add Foster Orientation to calendar"><i data-lucide="download"></i></button>
            </li>
          </ul>
        </div>
        <div class="side-card reveal">
          <div class="side-head"><i data-lucide="paw-print"></i><h3>Looking for a home</h3></div>
          <ul class="pet-list" id="petList"></ul>
        </div>
        <div class="side-card side-news reveal">
          <div class="side-head"><i data-lucide="send"></i><h3>The Weekly Wag</h3></div>
          <p>One email a week — care tips, new arrivals, and event invites. No spam, ever.</p>
          <form id="newsForm" novalidate>
            <input type="email" id="newsEmail" placeholder="you@example.com" aria-label="Email address" autocomplete="email">
            <button class="btn btn-primary" type="submit" aria-label="Subscribe"><i data-lucide="send"></i></button>
          </form>
          <p class="news-error" id="newsError" hidden>Please enter a valid email address.</p>
        </div>
      </aside>
    </div>
  </section>

  <!-- FAQ -->
  <section class="section" id="faq">
    <div class="container faq-wrap">
      <div class="section-head center reveal">
        <div>
          <p class="eyebrow">Good questions</p>
          <h2>Answers, before you even ask</h2>
        </div>
        <p class="section-lead">The things pet owners ask us most, answered by the people who answer them every day. Anything else — call <a href="tel:+15035550148">(503) 555-0148</a>; a human picks up.</p>
      </div>
      <div class="faq-list reveal">
        <div class="faq-item">
          <button class="faq-q" aria-expanded="false"><span>Do I need an appointment, or can I walk in?</span><span class="faq-ic"><i data-lucide="plus"></i></span></button>
          <div class="faq-a"><div class="faq-a-inner"><p>We reserve same-day slots for sick pets every morning and do our best to accommodate walk-ins, but booking ahead guarantees your spot. You can book online in under a minute using the scheduler above, or call (503) 555-0148 and we'll find a time that works.</p></div></div>
        </div>
        <div class="faq-item">
          <button class="faq-q" aria-expanded="false"><span>What should I bring to my first visit?</span><span class="faq-ic"><i data-lucide="plus"></i></span></button>
          <div class="faq-a"><div class="faq-a-inner"><p>Bring any previous medical records, a list of current medications, and your vaccination history if you have it. For puppies and kittens, a fresh stool sample helps us run the right screening. And bring your questions — first visits are a full 30 minutes precisely so nothing gets rushed.</p></div></div>
        </div>
        <div class="faq-item">
          <button class="faq-q" aria-expanded="false"><span>How does the adoption process work?</span><span class="faq-ic"><i data-lucide="plus"></i></span></button>
          <div class="faq-a"><div class="faq-a-inner"><p>It starts with a relaxed meet-and-greet — no pressure, no paperwork. If it's a match, we walk you through a short application, verify landlord policies or vet references where needed, and schedule a quick home-readiness check. Most adoptions finalize within a week. Your fee covers spay or neuter, vaccinations, microchipping, and a starter kit, plus free training classes for life.</p></div></div>
        </div>
        <div class="faq-item">
          <button class="faq-q" aria-expanded="false"><span>Are your trainers certified?</span><span class="faq-ic"><i data-lucide="plus"></i></span></button>
          <div class="faq-a"><div class="faq-a-inner"><p>Yes. Our lead trainers hold certifications from the Certification Council for Professional Dog Trainers (CPDT-KA) and the Karen Pryor Academy (KPA-CTP), and every program is force-free and reward-based. Our handling staff are Fear-Free® certified, so anxious pets get extra patience, breaks, and quiet rooms.</p></div></div>
        </div>
        <div class="faq-item">
          <button class="faq-q" aria-expanded="false"><span>What if my pet is sick after hours?</span><span class="faq-ic"><i data-lucide="plus"></i></span></button>
          <div class="faq-a"><div class="faq-a-inner"><p>Call us first at (503) 555-0148 — our voicemail tells you when to come straight in and when to go directly to our emergency partner, Cascade Emergency Animal Hospital, five minutes away. For suspected poisoning, the ASPCA Poison Control line (888) 426-4435 is staffed 24/7.</p></div></div>
        </div>
        <div class="faq-item">
          <button class="faq-q" aria-expanded="false"><span>Which neighborhoods do you serve?</span><span class="faq-ic"><i data-lucide="plus"></i></span></button>
          <div class="faq-a"><div class="faq-a-inner"><p>We're based in Maplewood and serve the greater Portland area — roughly a 15-mile radius. For adoptions, we also coordinate volunteer transport, so living across town is rarely a barrier. Training consults are available by video for the whole state.</p></div></div>
        </div>
      </div>
    </div>
  </section>

  <!-- CTA banner -->
  <section class="cta-wrap">
    <div class="container">
      <div class="cta-banner reveal">
        <i data-lucide="paw-print" class="cta-paw cta-paw-1"></i>
        <i data-lucide="paw-print" class="cta-paw cta-paw-2"></i>
        <h2>Whatever your pet needs next, we're ready.</h2>
        <p>Book a checkup, meet a new best friend, or talk through a problem you've been Googling at 2 AM — the first step is always a short conversation.</p>
        <div class="cta-actions">
          <a href="#book" class="btn btn-amber btn-lg">Book an Appointment <i data-lucide="calendar-check"></i></a>
          <button class="btn btn-outline-light btn-lg" id="ctaAdopt">Start an Adoption Application</button>
        </div>
        <p class="cta-call"><i data-lucide="phone"></i>Prefer to talk? Call (503) 555-0148 — 8 AM to 7 PM, Monday through Saturday.</p>
      </div>
    </div>
  </section>
</main>

<!-- Footer -->
<footer class="site-footer" id="contact">
  <div class="container">
    <div class="footer-grid">
      <div class="footer-brand">
        <img src="https://placehold.co/196x56/0E5F57/FFFFFF?text=PawHaven&amp;font=playfair+display" alt="PawHaven logo" width="196" height="56">
        <p>A neighborhood clinic, adoption center, and training studio — caring for Portland's pets since 2009. Every pet deserves a healthy, happy life.</p>
        <div class="socials">
          <a href="#" class="demo-link" aria-label="Facebook"><i data-lucide="facebook"></i></a>
          <a href="#" class="demo-link" aria-label="Instagram"><i data-lucide="instagram"></i></a>
          <a href="#" class="demo-link" aria-label="Twitter"><i data-lucide="twitter"></i></a>
          <a href="#" class="demo-link" aria-label="YouTube"><i data-lucide="youtube"></i></a>
        </div>
      </div>
      <nav class="footer-col" aria-label="Explore">
        <h4>Explore</h4>
        <a href="#home">Home</a>
        <a href="#services">Pet Care</a>
        <a href="#adoption">Adoption</a>
        <a href="#library">Blog</a>
        <a href="#faq">FAQ</a>
        <a href="#book">Book a Visit</a>
      </nav>
      <nav class="footer-col" aria-label="Services">
        <h4>Services</h4>
        <a href="#book">Wellness Exams</a>
        <a href="#book">Vaccinations</a>
        <a href="#book">Dental Care</a>
        <a href="#book">Grooming</a>
        <a href="#library">Nutrition Counseling</a>
        <a href="#adoption">Adoption</a>
      </nav>
      <div class="footer-col footer-contact">
        <h4>Visit us</h4>
        <p><i data-lucide="map-pin"></i><span>742 Maplewood Avenue<br>Portland, OR 97205</span></p>
        <p><i data-lucide="phone"></i><a href="tel:+15035550148">(503) 555-0148</a></p>
        <p><i data-lucide="mail"></i><a href="mailto:hello@pawhaven.com">hello@pawhaven.com</a></p>
        <p><i data-lucide="clock"></i><span>Mon–Fri 8 AM–7 PM · Sat 9 AM–5 PM · Sun closed</span></p>
      </div>
    </div>
    <div class="footer-bottom">
      <p>© <span id="year">2025</span> PawHaven Pet Care, LLC. All rights reserved.</p>
      <div class="footer-legal">
        <a href="#" class="demo-link">Privacy Policy</a>
        <a href="#" class="demo-link">Terms of Service</a>
        <a href="#" class="demo-link">Accessibility</a>
      </div>
    </div>
  </div>
</footer>

<!-- Modal -->
<div class="modal-overlay" id="modalOverlay" role="dialog" aria-modal="true" aria-label="Details">
  <div class="modal-panel">
    <button class="modal-close" id="modalClose" aria-label="Close"><i data-lucide="x"></i></button>
    <div id="modalBody"></div>
  </div>
</div>

<!-- Toast & back-to-top -->
<div class="toast" id="toast" role="status"><i data-lucide="badge-check"></i><span></span></div>
<button class="to-top" id="toTop" aria-label="Back to top"><i data-lucide="arrow-up"></i></button>

<noscript><style>.reveal{opacity:1}</style></noscript>
<script src="https://unpkg.com/lucide@latest"></script>
<script>
const $  = (s, c = document) => c.querySelector(s);
const $$ = (s, c = document) => [...c.querySelectorAll(s)];
const pic = (seed, w, h) => `https://picsum.photos/seed/${seed}/${w}/${h}.jpg`;
const escapeHtml = s => String(s).replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
function refreshIcons(){ if (window.lucide) lucide.createIcons(); }

/* ============ Toast ============ */
let toastTimer;
function toast(msg){
  const t = $('#toast');
  t.querySelector('span').textContent = msg;
  t.classList.add('show');
  clearTimeout(toastTimer);
  toastTimer = setTimeout(() => t.classList.remove('show'), 3400);
}

/* ============ Data ============ */
const SERVICES = [
  { id:'wellness',  name:'Wellness Exam',    price:65,  dur:'30 min'   },
  { id:'vaccine',   name:'Vaccination Visit',price:38,  dur:'20 min'   },
  { id:'dental',    name:'Dental Cleaning',  price:220, dur:'2–3 hrs'  },
  { id:'grooming',  name:'Grooming & Bath',  price:55,  dur:'1 hr'     },
  { id:'training',  name:'Training Consult', price:85,  dur:'45 min'   },
  { id:'adoption',  name:'Adoption Visit',   price:0,   dur:'45 min'   }
];
const TABS = [
  { id:'all',      label:'All Posts'   },
  { id:'dogs',     label:'Dogs'        },
  { id:'cats',     label:'Cats'        },
  { id:'senior',   label:'Senior Care' },
  { id:'training', label:'Training'    }
];
const POSTS = [
  {
    id:'golden', cat:'dogs', catLabel:'Dogs', read:'12 min read', date:'Jun 2, 2025', seed:'ph-golden',
    title:'The Golden Retriever, Explained: Health, Temperament & Daily Care',
    excerpt:`Friendly, biddable, and endlessly enthusiastic, Goldens are America's classic family dog — and a breed with very specific health and exercise needs. Here's what sixteen years of clinical records at PawHaven teach us about keeping them thriving.`,
    body:[
      `Golden Retrievers are the default recommendation for first-time dog owners for good reason: they're soft-mouthed, endlessly patient, and seem to reserve their full enthusiasm for the people they love. But those breed characteristics come with responsibilities. Goldens were bred to work alongside hunters for hours — which means a bored Golden, not a "bad" Golden, is a Golden who invents a job, usually chewing.`,
      `On the health side, our sixteen years of records point to three things worth planning for: hip and elbow dysplasia (ask us about PennHIP screening at four months, and keep your Golden lean), ear infections (a weekly ear-drying routine after baths prevents most of what we see), and cancer, which affects the breed at a higher rate than many — so we recommend twice-yearly wellness exams from age six rather than seven.`,
      `Exercise-wise, aim for 60–90 minutes a day split into two outings, plus brain work: retrieval games, scent games, training classes. A tired Golden is a quiet Golden. And start handling exercises early — touching paws, ears, and mouth daily — so grooming and vet visits stay low-stress for a seventy-pound adult.`
    ]
  },
  {
    id:'blink', cat:'cats', catLabel:'Cats', read:'7 min read', date:'May 19, 2025', seed:'ph-blink',
    title:`The Slow Blink: A Veterinarian's Guide to Reading Your Cat`,
    excerpt:`If you've ever looked at a relaxed cat and slowly blinked, you've already spoken Cat. The "slow blink" is what ethologists call a cat kiss — and research shows cats are far more likely to slow-blink back at humans who do it. Trust, made visible.`,
    body:[
      `The slow blink — eyes closing in a lazy, unhurried half-moon — is what ethologists call a "cat kiss." Researchers at the University of Sussex found that cats are significantly more likely to slow-blink at humans who slow-blink at them, and that this simple exchange measurably reduces tension between cats and the people they live with. It costs nothing and works at any age.`,
      `The rest of the vocabulary is just as readable once you know where to look. Forward-facing, upright ears with slow, lazy rotations mean "I'm comfortable." Ears flattened sideways — airplane ears — mean overstimulation or fear, and it's time to give space. A tail held high with a little curl at the tip is a greeting; a tail thumping on the floor is irritation. Cats don't wag when they're happy — they thump when they're done.`,
      `The most common mistake we see is punishing the warning signs. A cat that swats when its belly is touched isn't being "mean" — it's telling you that a hand moving toward its underside feels like a predator, because that's exactly where predators grab prey. Learning to read the quiet signals — the flicked tail, the suddenly still body, the half-lidded stare — prevents most of the "mystery" bites we treat.`
    ]
  },
  {
    id:'senior', cat:'senior', catLabel:'Senior Care', read:'10 min read', date:'May 5, 2025', seed:'ph-senior',
    title:`After Seven: How Your Pet's Needs Change in Their Senior Years`,
    excerpt:`Somewhere around age seven — earlier for giant breeds, later for some cats — your pet quietly becomes a senior. The rulebook changes: twice-yearly wellness exams, earlier screening, and a home that works a little harder for them.`,
    body:[
      `Somewhere around age seven — earlier for giant breeds, later for some cats — a pet crosses into their senior years, and the rulebook changes. What used to be a once-a-year visit becomes twice a year. Why? Because in a senior pet, six months is a meaningful slice of a lifespan, and the earlier we catch arthritis, kidney changes, dental disease, or cognitive shifts, the more options we have.`,
      `The most common senior condition we manage isn't dramatic — it's arthritis, present in the majority of cats over twelve and a large share of older dogs, and chronically underdiagnosed because pets rarely complain. The signs are subtle: hesitation at the stairs, a dog that "slows down" on walks, a cat that stops jumping to the counter, uneven grooming. Weight loss, increased thirst, and changes in sleep or litter-box habits deserve a call, not a wait-and-see.`,
      `The good news: senior is not the same as sick. Adjustments — life-stage nutrition with appropriate protein and joint support, ramps and heated beds, shorter but more frequent walks, night lights for early cognitive dysfunction — add years of comfort. Ask us about our Senior Wellness Plan, which bundles the twice-yearly exams, bloodwork, and blood-pressure checks most seniors need.`
    ]
  },
  {
    id:'social', cat:'training', catLabel:'Training', read:'9 min read', date:'Apr 21, 2025', seed:'ph-puppy',
    title:'The Socialization Window: What 8 to 16 Weeks Can Shape for Life',
    excerpt:`Between roughly eight and sixteen weeks, a puppy's brain is in its critical socialization window — a period when new experiences shape lifelong temperament with unusual permanence. Missed or mishandled, it produces the anxious dog who rehearses fear for years.`,
    body:[
      `Between roughly eight and sixteen weeks, a puppy's brain is in what behaviorists call the critical socialization window — a period when new experiences are filed away with unusual permanence. Well-handled, this window produces the confident dog who shrugs at vacuum cleaners and nail trims. Missed or mishandled, it produces the anxious dog who rehearses fear for years.`,
      `The recipe is exposure plus safety. We want dozens of positive encounters — different surfaces, sounds, people in hats and uniforms, friendly vaccinated dogs, car rides, stairs — each paired with treats, all before the window closes. Just as important is protecting puppies from overwhelming experiences during this period: one frightening event during a fear period (often around eight to ten weeks) can set a dog back months.`,
      `Puppy kindergarten isn't really about obedience — it's supervised socialization with a curriculum. Our classes cap at six puppies, require age-appropriate vaccinations, and focus as much on play skills and alone-time as on "sit." And if you've adopted an older rescue with gaps in early socialization, it's not too late — remedial socialization works at any age, it just takes more patience and a good trainer.`
    ]
  },
  {
    id:'label', cat:'dogs', catLabel:'Dogs', read:'8 min read', date:'Apr 7, 2025', seed:'ph-label',
    title:'How to Read a Pet Food Label (and What AAFCO Actually Means)',
    excerpt:`Pet food labels are marketing documents first and nutrition facts second — but a few regulated phrases are genuinely useful. Here's how to tell life-stage appropriate food from clever packaging, and why calories matter more than the ingredient list.`,
    body:[
      `Pet food labels are marketing first, nutrition second, but a few phrases are regulated and genuinely useful. The AAFCO statement — from the Association of American Feed Control Officials — tells you whether a food was formulated to meet a life-stage nutrient profile or actually tested in feeding trials. "Formulated" foods meet the targets on paper; foods that passed feeding trials were tested on real animals. For most healthy pets either is fine; for medical conditions, your vet may recommend a therapeutic diet, which is regulated like a drug.`,
      `Beyond AAFCO, learn the calorie statement — it's required, usually small, and expressed per cup or per can. "Lite" foods vary enormously, and two similar-looking foods can differ by 100+ kcal per cup, which is a pound of body weight over a few months on a small dog. Ingredients are listed by weight before cooking, so a fresh meat source can outrank a grain while contributing less nutrition than it appears to.`,
      `Life stage matters more than brand: puppies need food formulated for growth (or all life stages), adults need maintenance, and seniors often do best on adjusted protein, phosphorus, and added joint support. Treats and toppers should stay under 10% of daily calories. When in doubt, bring the label — or a photo of it — to your next wellness exam and we'll decode it together.`
    ]
  },
  {
    id:'litter', cat:'cats', catLabel:'Cats', read:'11 min read', date:'Mar 24, 2025', seed:'ph-litter',
    title:`Litter Box Problems? A Vet's Step-by-Step Troubleshooting Guide`,
    excerpt:`When a cat stops using the litter box, the internet wants you to buy different litter. Veterinarians want you to book an exam. In a meaningful share of cases, the first sign is medical — and the cat is trying to tell you the box itself hurts.`,
    body:[
      `When a cat stops using the litter box, the internet wants you to buy a different litter. Veterinarians want you to book an exam. Inappropriate elimination is one of the most common presentations we see, and in a meaningful share of cases the cause is medical — a urinary tract infection, crystals, or cystitis makes the box itself painful, and the cat begins associating the box with discomfort.`,
      `So step one is always a vet visit, ideally with a fresh urine sample. Once medical causes are ruled out or treated, the detective work begins: location (is the box next to the noisy furnace?), number of boxes (the rule is one per cat plus one), substrate (most cats prefer fine, unscented, clumping litter), and cleanliness (scoop daily, full change weekly). Stress — a new pet, a move, a visiting relative — is the most common behavioral driver, and it tends to show up as marking on vertical surfaces rather than missing the box.`,
      `Punishment never works and usually makes things worse: a cat doesn't connect the scolding with an accident hours ago, only with you. If the problem persists after a clean bill of health, ask about a behavior consult — most cases resolve with a combination of medical treatment, environmental changes, and, when needed, anti-anxiety support. The earlier we see it, the easier it is to fix.`
    ]
  }
];
const PETS = [
  {
    id:'biscuit', name:'Biscuit', breed:'Golden Retriever', age:'2 years', sex:'Male', seed:'ph-biscuit',
    tags:['Vaccinated','Neutered','Microchipped'], goodWith:['Kids','Dogs','Cats'],
    bio:`Biscuit is a certified goofball — a Golden Retriever who greets every morning like it's his birthday. He adores fetch, tolerates baths with surprising dignity, and has never met a stranger. He's looking for a family with a yard (or a nearby park) and someone who doesn't mind sharing the couch.`
  },
  {
    id:'clementine', name:'Clementine', breed:'Domestic Shorthair', age:'1 year', sex:'Female', seed:'ph-clementine',
    tags:['Vaccinated','Spayed','Microchipped'], goodWith:['Kids','Cats'],
    bio:`Clementine — "Clemmie" to her friends — is a one-year-old tuxedo with a motor that never idles. She'll chirp at birds from the windowsill at 6 AM sharp, then nap on a warm laptop at noon. She'd thrive as the queen of the household, or with a mellow cat sibling.`
  },
  {
    id:'pepper', name:'Pepper', breed:'Border Collie mix', age:'8 months', sex:'Female', seed:'ph-pepper',
    tags:['Vaccinated','Spayed','Microchipped'], goodWith:['Dogs','Adults'],
    bio:`Pepper is a brilliant, busy eight-month-old who learns a new trick in about four repetitions and then invents harder ones. She needs a job — agility, hiking, or a human who runs. Experience with herding breeds, or a firm commitment to our training classes, is a must.`
  }
];

/* ============ Header / nav ============ */
const header = $('#siteHeader'), toTop = $('#toTop');
window.addEventListener('scroll', () => {
  header.classList.toggle('scrolled', window.scrollY > 8);
  toTop.classList.toggle('show', window.scrollY > 700);
}, { passive:true });
toTop.addEventListener('click', () => window.scrollTo({ top:0, behavior:'smooth' }));

const nav = $('#mainNav'), menuToggle = $('#menuToggle');
menuToggle.addEventListener('click', () => {
  const open = nav.classList.toggle('open');
  menuToggle.classList.toggle('open', open);
  menuToggle.setAttribute('aria-expanded', open);
});
$$('#mainNav a').forEach(a => a.addEventListener('click', () => {
  nav.classList.remove('open');
  menuToggle.classList.remove('open');
  menuToggle.setAttribute('aria-expanded', 'false');
}));

/* ============ Reveal on scroll ============ */
$$('.stagger').forEach(g => $$('.reveal', g).forEach((el, i) => el.style.animationDelay = (i * 80) + 'ms'));
const revealIO = new IntersectionObserver(entries => {
  entries.forEach(en => {
    if (!en.isIntersecting) return;
    const el = en.target;
    el.classList.add('in');
    el.addEventListener('animationend', function h(e){
      if (e.animationName === 'rise'){ el.classList.add('done'); el.classList.remove('in'); el.removeEventListener('animationend', h); }
    });
    revealIO.unobserve(el);
  });
}, { threshold:.12, rootMargin:'0px 0px -30px 0px' });
$$('.reveal').forEach(el => revealIO.observe(el));

/* ============ Stat count-up ============ */
function countUp(el){
  const target = parseFloat(el.dataset.count), suffix = el.dataset.suffix || '';
  const dur = 1400, start = performance.now();
  function tick(now){
    const p = Math.min((now - start) / dur, 1);
    const eased = 1 - Math.pow(1 - p, 3);
    el.textContent = Math.round(target * eased).toLocaleString('en-US') + suffix;
    if (p < 1) requestAnimationFrame(tick);
  }
  requestAnimationFrame(tick);
}
const statsIO = new IntersectionObserver(es => {
  es.forEach(en => { if (en.isIntersecting){ $$('[data-count]').forEach(countUp); statsIO.disconnect(); } });
}, { threshold:.4 });
statsIO.observe($('#statsCard'));

/* ============ Appointment scheduler ============ */
const booking = { service:null, date:null, dateLabel:null, time:null, pet:'', owner:'', phone:'' };
const dateKey = d => d.getFullYear() + '-' + (d.getMonth()+1) + '-' + d.getDate();
function hash(s){ let h = 7; for (let i = 0; i < s.length; i++){ h = (h * 31 + s.charCodeAt(i)) >>> 0; } return h; }
function buildSlots(){
  const out = []; let t = 8 * 60;
  while (t <= 17 * 60 + 45){
    const h = Math.floor(t / 60), m = t % 60;
    out.push({ label: ((h % 12) || 12) + ':' + String(m).padStart(2,'0') + ' ' + (h < 12 ? 'AM' : 'PM'), minutes:t });
    t += 45;
  }
  return out;
}
const isBooked = (key, label) => hash(key + label) % 10 < 3;

function renderServices(){
  const wrap = $('#servicePills'); wrap.innerHTML = '';
  SERVICES.forEach(s => {
    const b = document.createElement('button');
    b.type = 'button';
    b.className = 'pill' + (booking.service === s.id ? ' selected' : '');
    b.innerHTML = `${s.name} <span>·</span> ${s.price === 0 ? 'Free' : '$' + s.price}`;
    b.addEventListener('click', () => { booking.service = s.id; renderServices(); updateSummary(); });
    wrap.appendChild(b);
  });
}
function renderDates(){
  const row = $('#dateRow'); row.innerHTML = '';
  const today = new Date();
  for (let i = 0; i < 14; i++){
    const d = new Date(today); d.setDate(today.getDate() + i);
    const key = dateKey(d), closed = d.getDay() === 0;
    const b = document.createElement('button');
    b.type = 'button';
    b.className = 'date-chip' + (booking.date === key ? ' selected' : '');
    b.innerHTML = `<span>${i === 0 ? 'Today' : d.toLocaleDateString('en-US',{weekday:'short'})}</span><strong>${d.toLocaleDateString('en-US',{month:'short',day:'numeric'})}</strong>`;
    if (closed){ b.disabled = true; b.querySelector('strong').textContent = 'Closed'; }
    else b.addEventListener('click', () => {
      booking.date = key;
      booking.dateLabel = d.toLocaleDateString('en-US',{weekday:'long',month:'long',day:'numeric'});
      booking.time = null;
      renderDates(); renderTimes(); updateSummary();
    });
    row.appendChild(b);
  }
}
function renderTimes(){
  const grid = $('#timeGrid');
  if (!booking.date){ grid.innerHTML = '<p class="time-hint">Choose a day above to see open times.</p>'; return; }
  grid.innerHTML = '';
  const now = new Date(), isToday = dateKey(now) === booking.date;
  buildSlots().forEach(s => {
    const booked = isBooked(booking.date, s.label);
    const past = isToday && s.minutes <= now.getHours() * 60 + now.getMinutes() + 60;
    const b = document.createElement('button');
    b.type = 'button';
    b.className = 'time-slot' + (booking.time === s.label ? ' selected' : '');
    b.textContent = s.label;
    if (booked){ b.disabled = true; b.title = 'Already booked'; }
    else if (past){ b.disabled = true; b.title = 'Too soon — pick a later time'; }
    else b.addEventListener('click', () => { booking.time = s.label; renderTimes(); updateSummary(); });
    grid.appendChild(b);
  });
}
function updateSummary(){
  const svc = SERVICES.find(s => s.id === booking.service);
  $('#sumService').textContent = svc ? svc.name : '—';
  $('#sumDate').textContent    = booking.dateLabel || '—';
  $('#sumTime').textContent    = booking.time || '—';
  $('#sumPet').textContent     = booking.pet ? `${booking.pet} · ${$('#petType').value}` : '—';
  $('#sumOwner').textContent   = booking.owner || '—';
  $('#sumPrice').textContent   = svc ? (svc.price === 0 ? 'Free' : '$' + svc.price) : '—';
}
function findNextOpening(){
  const now = new Date(), nm = now.getHours() * 60 + now.getMinutes();
  for (let i = 0; i < 14; i++){
    const d = new Date(now); d.setDate(now.getDate() + i);
    if (d.getDay() === 0) continue;
    const key = dateKey(d);
    const avail = buildSlots().filter(s => !isBooked(key, s.label) && (i > 0 || s.minutes > nm + 30));
    if (avail.length){
      const when = i === 0 ? 'Today' : d.toLocaleDateString('en-US',{weekday:'short'});
      return when + ' · ' + avail[0].label;
    }
  }
  return 'Call (503) 555-0148';
}
$('#petName').addEventListener('input', e => { booking.pet = e.target.value; e.target.classList.remove('invalid'); updateSummary(); });
$('#ownerName').addEventListener('input', e => { booking.owner = e.target.value; e.target.classList.remove('invalid'); updateSummary(); });
$('#ownerPhone').addEventListener('input', e => { booking.phone = e.target.value; e.target.classList.remove('invalid'); updateSummary(); });
$('#petType').addEventListener('change', updateSummary);

$('#bookForm').addEventListener('submit', e => {
  e.preventDefault();
  const pet = $('#petName'), owner = $('#ownerName'), phone = $('#ownerPhone');
  [pet, owner, phone].forEach(i => i.classList.remove('invalid'));
  const missing = [];
  if (!booking.service) missing.push('service');
  if (!booking.date) missing.push('day');
  if (!booking.time) missing.push('time');
  if (!pet.value.trim()){ pet.classList.add('invalid'); missing.push('pet'); }
  if (!owner.value.trim()){ owner.classList.add('invalid'); missing.push('owner'); }
  if (phone.value.replace(/\D/g,'').length < 7){ phone.classList.add('invalid'); missing.push('phone'); }
  const err = $('#bookError');
  if (missing.length){
    err.hidden = false;
    const w = $('#bookWidget');
    w.classList.remove('shake'); void w.offsetWidth; w.classList.add('shake');
    return;
  }
  err.hidden = true;
  booking.pet = pet.value.trim(); booking.owner = owner.value.trim(); booking.phone = phone.value.trim();
  const svc = SERVICES.find(s => s.id === booking.service);
  const ref = 'PH-' + new Date().getFullYear() + '-' + Math.floor(1000 + Math.random() * 9000);
  const first = escapeHtml(booking.owner.split(' ')[0]);
  $('#bookSuccess').innerHTML = `
    <div class="success-inner">
      <svg class="check-svg" viewBox="0 0 56 56" aria-hidden="true"><circle cx="28" cy="28" r="25"/><path d="M17.5 29.5l7.5 7.5 14-15"/></svg>
      <h3>You're on the books, ${first}!</h3>
      <p>We've requested <strong>${svc.name}</strong> for <strong>${escapeHtml(booking.pet)} (${$('#petType').value})</strong> on <strong>${booking.dateLabel}</strong> at <strong>${booking.time}</strong>. A confirmation text is on its way to <strong>${escapeHtml(booking.phone)}</strong>.</p>
      <div class="ref-chip">Reference&nbsp;<strong>${ref}</strong></div>
      <p class="success-small">Need to change something? Reschedule free up to 12 hours ahead — call (503) 555-0148.</p>
      <div class="success-actions">
        <button class="btn btn-primary" id="bookAgain">Book another visit</button>
        <a href="#library" class="btn btn-ghost">Read the Journal</a>
      </div>
    </div>`;
  $('#bookGrid').hidden = true;
  $('#bookSuccess').hidden = false;
  $('#bookAgain').addEventListener('click', resetBooking);
  toast('Appointment request sent — watch for our confirmation text.');
});
function resetBooking(){
  booking.service = null; booking.date = null; booking.dateLabel = null; booking.time = null;
  $('#bookForm').reset();
  $$('.invalid', $('#bookForm')).forEach(i => i.classList.remove('invalid'));
  $('#bookError').hidden = true;
  renderServices(); renderDates(); renderTimes(); updateSummary();
  $('#bookSuccess').hidden = true;
  $('#bookGrid').hidden = false;
}
function startApplication(petName){
  booking.service = 'adoption';
  renderServices(); updateSummary(); closeModal();
  $('#book').scrollIntoView({ behavior:'smooth' });
  const w = $('#bookWidget');
  w.classList.remove('flash'); void w.offsetWidth; w.classList.add('flash');
  toast(petName ? `Adoption Visit selected — tell us about ${petName} in the form.` : 'Adoption Visit selected — tell us about your future pet in the form.');
}
$('#adoptCtaBtn').addEventListener('click', () => startApplication(''));
$('#ctaAdopt').addEventListener('click', () => startApplication(''));

/* ============ Journal tabs & posts ============ */
let activeTab = 'all';
function renderTabs(){
  const tabs = $('#postTabs'); tabs.innerHTML = '';
  TABS.forEach(t => {
    const b = document.createElement('button');
    b.className = 'tab' + (activeTab === t.id ? ' active' : '');
    b.setAttribute('role','tab');
    b.setAttribute('aria-selected', activeTab === t.id);
    b.textContent = t.label;
    b.addEventListener('click', () => { activeTab = t.id; renderTabs(); renderPosts(); });
    tabs.appendChild(b);
  });
}
function renderPosts(){
  const grid = $('#postsGrid'); grid.innerHTML = '';
  const list = activeTab === 'all' ? POSTS : POSTS.filter(p => p.cat === activeTab);
  list.forEach((p, i) => {
    const el = document.createElement('article');
    el.className = 'post-card';
    el.tabIndex = 0;
    el.setAttribute('role','button');
    el.setAttribute('aria-label', 'Read guide: ' + p.title);
    el.style.animationDelay = (i * 70) + 'ms';
    el.innerHTML = `
      <div class="post-media"><img src="${pic(p.seed,640,400)}" alt="${escapeHtml(p.title)}" loading="lazy"><span class="post-chip">${p.catLabel}</span></div>
      <div class="post-body">
        <div class="post-meta"><i data-lucide="clock"></i><span>${p.read}</span><span class="dot"></span><span>${p.date}</span></div>
        <h3>${p.title}</h3>
        <p>${p.excerpt}</p>
        <span class="text-link">Read guide <i data-lucide="arrow-right"></i></span>
      </div>`;
    const open = () => openPost(p);
    el.addEventListener('click', open);
    el.addEventListener('keydown', e => { if (e.key === 'Enter' || e.key === ' '){ e.preventDefault(); open(); } });
    grid.appendChild(el);
  });
  refreshIcons();
}
$('#browseAll').addEventListener('click', () => toast("You're viewing 6 of 42 guides — the full Journal library launches this summer."));

/* ============ Sidebar pets ============ */
function renderPets(){
  const list = $('#petList'); list.innerHTML = '';
  PETS.forEach(p => {
    const li = document.createElement('li');
    li.className = 'pet-row';
    li.innerHTML = `
      <img src="${pic(p.seed,120,120)}" alt="${p.name}, ${p.breed}" loading="lazy">
      <div><strong>${p.name}</strong><br><span>${p.breed} · ${p.age}</span></div>
      <button class="pet-meet" data-pet="${p.id}">Meet</button>`;
    li.querySelector('button').addEventListener('click', () => openPet(p));
    list.appendChild(li);
  });
}

/* ============ Modal ============ */
const overlay = $('#modalOverlay');
function openModal(html){
  $('#modalBody').innerHTML = html;
  overlay.classList.add('open');
  document.body.style.overflow = 'hidden';
  refreshIcons();
  $('#modalClose').focus();
}
function closeModal(){
  overlay.classList.remove('open');
  document.body.style.overflow = '';
}
$('#modalClose').addEventListener('click', closeModal);
overlay.addEventListener('click', e => { if (e.target === overlay) closeModal(); });
document.addEventListener('keydown', e => { if (e.key === 'Escape' && overlay.classList.contains('open')) closeModal(); });
$('#modalBody').addEventListener('click', e => {
  if (e.target.closest('[data-close]')) closeModal();
  const ap = e.target.closest('[data-apply]');
  if (ap) startApplication(ap.dataset.apply || '');
});
function openPost(p){
  openModal(`
    <img class="modal-img" src="${pic(p.seed,900,520)}" alt="${escapeHtml(p.title)}">
    <div class="modal-pad">
      <div class="modal-meta"><span class="post-chip static">${p.catLabel}</span><span class="modal-meta-text">${p.read} · ${p.date} · by the PawHaven team</span></div>
      <h3 class="modal-title">${p.title}</h3>
      ${p.body.map(t => `<p>${t}</p>`).join('')}
      <div class="modal-foot">
        <a href="#library" class="btn btn-ghost" data-close>Back to the Journal</a>
        <a href="#book" class="btn btn-primary" data-close>Book a visit <i data-lucide="arrow-right"></i></a>
      </div>
    </div>`);
}
function openPet(p){
  openModal(`
    <div class="modal-pad">
      <div class="pet-head">
        <img src="${pic(p.seed,240,240)}" alt="${p.name}">
        <div>
          <h3 class="modal-title" style="margin-bottom:2px">${p.name}</h3>
          <p class="pet-sub">${p.breed} · ${p.age} · ${p.sex}</p>
          <div class="pet-tags">${p.tags.map(t => `<span>${t}</span>`).join('')}</div>
        </div>
      </div>
      <p>${p.bio}</p>
      <p class="pet-good"><strong>Good with:</strong> ${p.goodWith.join(' · ')}</p>
      <button class="btn btn-primary btn-block" data-apply="${p.name}">Start an application for ${p.name} <i data-lucide="arrow-right"></i></button>
      <p class="success-small" style="text-align:center;margin-top:12px">Applying is free and takes about 10 minutes. We call within one business day.</p>
    </div>`);
}

/* ============ FAQ accordion ============ */
$$('.faq-item').forEach(item => {
  const btn = $('.faq-q', item);
  btn.addEventListener('click', () => {
    const wasOpen = item.classList.contains('open');
    $$('.faq-item.open').forEach(o => { o.classList.remove('open'); $('.faq-q', o).setAttribute('aria-expanded','false'); });
    if (!wasOpen){ item.classList.add('open'); btn.setAttribute('aria-expanded','true'); }
  });
});

/* ============ Newsletter ============ */
$('#newsForm').addEventListener('submit', e => {
  e.preventDefault();
  const em = $('#newsEmail'), err = $('#newsError');
  const ok = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(em.value.trim());
  if (!ok){ err.hidden = false; em.classList.add('invalid'); em.focus(); return; }
  err.hidden = true;
  $('#newsForm').outerHTML = '<p class="news-done"><i data-lucide="badge-check"></i>You\'re on the list! The next issue lands Friday.</p>';
  refreshIcons();
  toast('Welcome to The Weekly Wag — see you Friday.');
});
$('#newsEmail').addEventListener('input', e => { e.target.classList.remove('invalid'); $('#newsError').hidden = true; });

/* ============ Calendar (.ics) downloads ============ */
function icsNow(){
  const d = new Date(), p = n => String(n).padStart(2,'0');
  return d.getFullYear() + p(d.getMonth()+1) + p(d.getDate()) + 'T' + p(d.getHours()) + p(d.getMinutes()) + p(d.getSeconds());
}
$$('.event-ics').forEach(b => b.addEventListener('click', () => {
  const d = b.dataset;
  const ics = ['BEGIN:VCALENDAR','VERSION:2.0','PRODID:-//PawHaven//EN','BEGIN:VEVENT',
    'UID:' + Date.now() + '@pawhaven.example','DTSTAMP:' + icsNow(),
    'DTSTART:' + d.start,'DTEND:' + d.end,'SUMMARY:' + d.title,
    'LOCATION:' + d.loc,'DESCRIPTION:Hosted by PawHaven Pet Care — 742 Maplewood Avenue, Portland, OR.',
    'END:VEVENT','END:VCALENDAR'].join('\r\n');
  const blob = new Blob([ics], { type:'text/calendar' });
  const a = document.createElement('a');
  a.href = URL.createObjectURL(blob);
  a.download = d.title.toLowerCase().replace(/[^a-z0-9]+/g,'-') + '.ics';
  document.body.appendChild(a); a.click(); a.remove();
  setTimeout(() => URL.revokeObjectURL(a.href), 800);
  toast('Calendar file downloaded — see you at the event!');
}));

/* ============ Demo links ============ */
$$('.demo-link').forEach(a => a.addEventListener('click', e => {
  e.preventDefault();
  toast("This is a design preview — that page isn't wired up yet.");
}));

/* ============ Init ============ */
renderServices(); renderDates(); renderTimes(); updateSummary();
renderTabs(); renderPosts(); renderPets();
$('#nextOpen').textContent = findNextOpening();
$('#year').textContent = new Date().getFullYear();
refreshIcons();
</script>
</body>
</html>
View Axe Report (JSON)
{
  "testEngine": {
    "name": "axe-core",
    "version": "4.10.2"
  },
  "testRunner": {
    "name": "axe"
  },
  "testEnvironment": {
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36",
    "windowWidth": 1280,
    "windowHeight": 720,
    "orientationAngle": 0,
    "orientationType": "landscape-primary"
  },
  "timestamp": "2026-11-12T10:12:06.785Z",
  "url": "https://benchmark.aimac.invalid/08c665a7a498163530ef7a34f11b837a35bef9fbd10de1f7799e27277e8f5293.html",
  "toolOptions": {
    "runOnly": {
      "type": "tag",
      "values": [
        "wcag2a",
        "wcag2aa",
        "wcag21a",
        "wcag21aa",
        "wcag22a",
        "wcag22aa"
      ]
    },
    "resultTypes": [
      "violations"
    ],
    "reporter": "v1"
  },
  "inapplicable": [
    {
      "id": "area-alt",
      "impact": null,
      "tags": [
        "cat.text-alternatives",
        "wcag2a",
        "wcag244",
        "wcag412",
        "section508",
        "section508.22.a",
        "TTv5",
        "TT6.a",
        "EN-301-549",
        "EN-9.2.4.4",
        "EN-9.4.1.2",
        "ACT"
      ],
      "description": "Ensure <area> elements of image maps have alternative text",
      "help": "Active <area> elements must have alternative text",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/area-alt?application=axeAPI",
      "nodes": []
    },
    {
      "id": "aria-braille-equivalent",
      "impact": null,
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag412",
        "EN-301-549",
        "EN-9.4.1.2"
      ],
      "description": "Ensure aria-braillelabel and aria-brailleroledescription have a non-braille equivalent",
      "help": "aria-braille attributes must have a non-braille equivalent",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-braille-equivalent?application=axeAPI",
      "nodes": []
    },
    {
      "id": "aria-input-field-name",
      "impact": null,
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag412",
        "TTv5",
        "TT5.c",
        "EN-301-549",
        "EN-9.4.1.2",
        "ACT"
      ],
      "description": "Ensure every ARIA input field has an accessible name",
      "help": "ARIA input fields must have an accessible name",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-input-field-name?application=axeAPI",
      "nodes": []
    },
    {
      "id": "aria-meter-name",
      "impact": null,
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag111",
        "EN-301-549",
        "EN-9.1.1.1"
      ],
      "description": "Ensure every ARIA meter node has an accessible name",
      "help": "ARIA meter nodes must have an accessible name",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-meter-name?application=axeAPI",
      "nodes": []
    },
    {
      "id": "aria-progressbar-name",
      "impact": null,
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag111",
        "EN-301-549",
        "EN-9.1.1.1"
      ],
      "description": "Ensure every ARIA progressbar node has an accessible name",
      "help": "ARIA progressbar nodes must have an accessible name",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-progressbar-name?application=axeAPI",
      "nodes": []
    },
    {
      "id": "aria-toggle-field-name",
      "impact": null,
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag412",
        "TTv5",
        "TT5.c",
        "EN-301-549",
        "EN-9.4.1.2",
        "ACT"
      ],
      "description": "Ensure every ARIA toggle field has an accessible name",
      "help": "ARIA toggle fields must have an accessible name",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-toggle-field-name?application=axeAPI",
      "nodes": []
    },
    {
      "id": "aria-tooltip-name",
      "impact": null,
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag412",
        "EN-301-549",
        "EN-9.4.1.2"
      ],
      "description": "Ensure every ARIA tooltip node has an accessible name",
      "help": "ARIA tooltip nodes must have an accessible name",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-tooltip-name?application=axeAPI",
      "nodes": []
    },
    {
      "id": "blink",
      "impact": null,
      "tags": [
        "cat.time-and-media",
        "wcag2a",
        "wcag222",
        "section508",
        "section508.22.j",
        "TTv5",
        "TT2.b",
        "EN-301-549",
        "EN-9.2.2.2"
      ],
      "description": "Ensure <blink> elements are not used",
      "help": "<blink> elements are deprecated and must not be used",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/blink?application=axeAPI",
      "nodes": []
    },
    {
      "id": "definition-list",
      "impact": null,
      "tags": [
        "cat.structure",
        "wcag2a",
        "wcag131",
        "EN-301-549",
        "EN-9.1.3.1"
      ],
      "description": "Ensure <dl> elements are structured correctly",
      "help": "<dl> elements must only directly contain properly-ordered <dt> and <dd> groups, <script>, <template> or <div> elements",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/definition-list?application=axeAPI",
      "nodes": []
    },
    {
      "id": "dlitem",
      "impact": null,
      "tags": [
        "cat.structure",
        "wcag2a",
        "wcag131",
        "EN-301-549",
        "EN-9.1.3.1"
      ],
      "description": "Ensure <dt> and <dd> elements are contained by a <dl>",
      "help": "<dt> and <dd> elements must be contained by a <dl>",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/dlitem?application=axeAPI",
      "nodes": []
    },
    {
      "id": "frame-focusable-content",
      "impact": null,
      "tags": [
        "cat.keyboard",
        "wcag2a",
        "wcag211",
        "TTv5",
        "TT4.a",
        "EN-301-549",
        "EN-9.2.1.1"
      ],
      "description": "Ensure <frame> and <iframe> elements with focusable content do not have tabindex=-1",
      "help": "Frames with focusable content must not have tabindex=-1",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/frame-focusable-content?application=axeAPI",
      "nodes": []
    },
    {
      "id": "frame-title-unique",
      "impact": null,
      "tags": [
        "cat.text-alternatives",
        "wcag2a",
        "wcag412",
        "TTv5",
        "TT12.d",
        "EN-301-549",
        "EN-9.4.1.2"
      ],
      "description": "Ensure <iframe> and <frame> elements contain a unique title attribute",
      "help": "Frames must have a unique title attribute",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/frame-title-unique?application=axeAPI",
      "nodes": []
    },
    {
      "id": "frame-title",
      "impact": null,
      "tags": [
        "cat.text-alternatives",
        "wcag2a",
        "wcag412",
        "section508",
        "section508.22.i",
        "TTv5",
        "TT12.d",
        "EN-301-549",
        "EN-9.4.1.2"
      ],
      "description": "Ensure <iframe> and <frame> elements have an accessible name",
      "help": "Frames must have an accessible name",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/frame-title?application=axeAPI",
      "nodes": []
    },
    {
      "id": "html-xml-lang-mismatch",
      "impact": null,
      "tags": [
        "cat.language",
        "wcag2a",
        "wcag311",
        "EN-301-549",
        "EN-9.3.1.1",
        "ACT"
      ],
      "description": "Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page",
      "help": "HTML elements with lang and xml:lang must have the same base language",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/html-xml-lang-mismatch?application=axeAPI",
      "nodes": []
    },
    {
      "id": "input-button-name",
      "impact": null,
      "tags": [
        "cat.name-role-value",
        "wcag2a",
        "wcag412",
        "section508",
        "section508.22.a",
        "TTv5",
        "TT5.c",
        "EN-301-549",
        "EN-9.4.1.2",
        "ACT"
      ],
      "description": "Ensure input buttons have discernible text",
      "help": "Input buttons must have discernible text",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/input-button-name?application=axeAPI",
      "nodes": []
    },
    {
      "id": "input-image-alt",
      "impact": null,
      "tags": [
        "cat.text-alternatives",
        "wcag2a",
        "wcag111",
        "wcag412",
        "section508",
        "section508.22.a",
        "TTv5",
        "TT7.a",
        "EN-301-549",
        "EN-9.1.1.1",
        "EN-9.4.1.2",
        "ACT"
      ],
      "description": "Ensure <input type=\"image\"> elements have alternative text",
      "help": "Image buttons must have alternative text",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/input-image-alt?application=axeAPI",
      "nodes": []
    },
    {
      "id": "link-in-text-block",
      "impact": null,
      "tags": [
        "cat.color",
        "wcag2a",
        "wcag141",
        "TTv5",
        "TT13.a",
        "EN-301-549",
        "EN-9.1.4.1"
      ],
      "description": "Ensure links are distinguished from surrounding text in a way that does not rely on color",
      "help": "Links must be distinguishable without relying on color",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/link-in-text-block?application=axeAPI",
      "nodes": []
    },
    {
      "id": "marquee",
      "impact": null,
      "tags": [
        "cat.parsing",
        "wcag2a",
        "wcag222",
        "TTv5",
        "TT2.b",
        "EN-301-549",
        "EN-9.2.2.2"
      ],
      "description": "Ensure <marquee> elements are not used",
      "help": "<marquee> elements are deprecated and must not be used",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/marquee?application=axeAPI",
      "nodes": []
    },
    {
      "id": "meta-refresh",
      "impact": null,
      "tags": [
        "cat.time-and-media",
        "wcag2a",
        "wcag221",
        "TTv5",
        "TT8.a",
        "EN-301-549",
        "EN-9.2.2.1"
      ],
      "description": "Ensure <meta http-equiv=\"refresh\"> is not used for delayed refresh",
      "help": "Delayed refresh under 20 hours must not be used",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/meta-refresh?application=axeAPI",
      "nodes": []
    },
    {
      "id": "object-alt",
      "impact": null,
      "tags": [
        "cat.text-alternatives",
        "wcag2a",
        "wcag111",
        "section508",
        "section508.22.a",
        "EN-301-549",
        "EN-9.1.1.1"
      ],
      "description": "Ensure <object> elements have alternative text",
      "help": "<object> elements must have alternative text",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/object-alt?application=axeAPI",
      "nodes": []
    },
    {
      "id": "role-img-alt",
      "impact": null,
      "tags": [
        "cat.text-alternatives",
        "wcag2a",
        "wcag111",
        "section508",
        "section508.22.a",
        "TTv5",
        "TT7.a",
        "EN-301-549",
        "EN-9.1.1.1",
        "ACT"
      ],
      "description": "Ensure [role=\"img\"] elements have alternative text",
      "help": "[role=\"img\"] elements must have an alternative text",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/role-img-alt?application=axeAPI",
      "nodes": []
    },
    {
      "id": "server-side-image-map",
      "impact": null,
      "tags": [
        "cat.text-alternatives",
        "wcag2a",
        "wcag211",
        "section508",
        "section508.22.f",
        "TTv5",
        "TT4.a",
        "EN-301-549",
        "EN-9.2.1.1"
      ],
      "description": "Ensure that server-side image maps are not used",
      "help": "Server-side image maps must not be used",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/server-side-image-map?application=axeAPI",
      "nodes": []
    },
    {
      "id": "summary-name",
      "impact": null,
      "tags": [
        "cat.name-role-value",
        "wcag2a",
        "wcag412",
        "section508",
        "section508.22.a",
        "TTv5",
        "TT6.a",
        "EN-301-549",
        "EN-9.4.1.2"
      ],
      "description": "Ensure summary elements have discernible text",
      "help": "Summary elements must have discernible text",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/summary-name?application=axeAPI",
      "nodes": []
    },
    {
      "id": "svg-img-alt",
      "impact": null,
      "tags": [
        "cat.text-alternatives",
        "wcag2a",
        "wcag111",
        "section508",
        "section508.22.a",
        "TTv5",
        "TT7.a",
        "EN-301-549",
        "EN-9.1.1.1",
        "ACT"
      ],
      "description": "Ensure <svg> elements with an img, graphics-document or graphics-symbol role have an accessible text",
      "help": "<svg> elements with an img role must have an alternative text",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/svg-img-alt?application=axeAPI",
      "nodes": []
    },
    {
      "id": "td-headers-attr",
      "impact": null,
      "tags": [
        "cat.tables",
        "wcag2a",
        "wcag131",
        "section508",
        "section508.22.g",
        "TTv5",
        "TT14.b",
        "EN-301-549",
        "EN-9.1.3.1"
      ],
      "description": "Ensure that each cell in a table that uses the headers attribute refers only to other cells in that table",
      "help": "Table cells that use the headers attribute must only refer to cells in the same table",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/td-headers-attr?application=axeAPI",
      "nodes": []
    },
    {
      "id": "th-has-data-cells",
      "impact": null,
      "tags": [
        "cat.tables",
        "wcag2a",
        "wcag131",
        "section508",
        "section508.22.g",
        "TTv5",
        "TT14.b",
        "EN-301-549",
        "EN-9.1.3.1"
      ],
      "description": "Ensure that <th> elements and elements with role=columnheader/rowheader have data cells they describe",
      "help": "Table headers in a data table must refer to data cells",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/th-has-data-cells?application=axeAPI",
      "nodes": []
    },
    {
      "id": "valid-lang",
      "impact": null,
      "tags": [
        "cat.language",
        "wcag2aa",
        "wcag312",
        "TTv5",
        "TT11.b",
        "EN-301-549",
        "EN-9.3.1.2",
        "ACT"
      ],
      "description": "Ensure lang attributes have valid values",
      "help": "lang attribute must have a valid value",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/valid-lang?application=axeAPI",
      "nodes": []
    },
    {
      "id": "video-caption",
      "impact": null,
      "tags": [
        "cat.text-alternatives",
        "wcag2a",
        "wcag122",
        "section508",
        "section508.22.a",
        "TTv5",
        "TT17.a",
        "EN-301-549",
        "EN-9.1.2.2"
      ],
      "description": "Ensure <video> elements have captions",
      "help": "<video> elements must have captions",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/video-caption?application=axeAPI",
      "nodes": []
    },
    {
      "id": "no-autoplay-audio",
      "impact": null,
      "tags": [
        "cat.time-and-media",
        "wcag2a",
        "wcag142",
        "TTv5",
        "TT2.a",
        "EN-301-549",
        "EN-9.1.4.2",
        "ACT"
      ],
      "description": "Ensure <video> or <audio> elements do not autoplay audio for more than 3 seconds without a control mechanism to stop or mute the audio",
      "help": "<video> or <audio> elements must not play automatically",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/no-autoplay-audio?application=axeAPI",
      "nodes": []
    }
  ],
  "passes": [
    {
      "id": "aria-allowed-attr",
      "impact": null,
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag412",
        "EN-301-549",
        "EN-9.4.1.2"
      ],
      "description": "Ensure an element's role supports its ARIA attributes",
      "help": "Elements must only use supported ARIA attributes",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-allowed-attr?application=axeAPI",
      "nodes": [
        {
          "any": [],
          "all": [
            {
              "id": "aria-allowed-attr",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "ARIA attributes are used correctly for the defined role"
            }
          ],
          "none": [
            {
              "id": "aria-unsupported-attr",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "ARIA attribute is supported"
            }
          ],
          "impact": null,
          "html": "<a href=\"#home\" class=\"brand\" aria-label=\"PawHaven \u2014 home\">\n      <img src=\"https://placehold.co/196x56/0E5F57/FFFFFF?text=PawHaven&amp;font=playfair+display\" alt=\"PawHaven logo\" width=\"196\" height=\"56\">\n    </a>",
          "target": [
            ".brand"
          ]
        }
      ]
    },
    {
      "id": "aria-command-name",
      "impact": null,
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag412",
        "TTv5",
        "TT6.a",
        "EN-301-549",
        "EN-9.4.1.2",
        "ACT"
      ],
      "description": "Ensure every ARIA button, link and menuitem has an accessible name",
      "help": "ARIA commands must have an accessible name",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-command-name?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "has-visible-text",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "Element has text that is visible to screen readers"
            },
            {
              "id": "aria-label",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "aria-label attribute exists and is not empty"
            }
          ],
          "all": [],
          "none": [],
          "impact": null,
          "html": "<article class=\"post-card\" tabindex=\"0\" role=\"button\" aria-label=\"Read guide: The Golden Retriever, Explained: Health, Temperament &amp; Daily Care\" style=\"animation-delay: 0ms;\">",
          "target": [
            ".post-card[role=\"button\"]:nth-child(1)"
          ]
        }
      ]
    },
    {
      "id": "aria-conditional-attr",
      "impact": null,
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag412",
        "EN-301-549",
        "EN-9.4.1.2"
      ],
      "description": "Ensure ARIA attributes are used as described in the specification of the element's role",
      "help": "ARIA attributes must be used as specified for the element's role",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-conditional-attr?application=axeAPI",
      "nodes": [
        {
          "any": [],
          "all": [
            {
              "id": "aria-conditional-attr",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "ARIA attribute is allowed"
            }
          ],
          "none": [],
          "impact": null,
          "html": "<a href=\"#home\" class=\"brand\" aria-label=\"PawHaven \u2014 home\">\n      <img src=\"https://placehold.co/196x56/0E5F57/FFFFFF?text=PawHaven&amp;font=playfair+display\" alt=\"PawHaven logo\" width=\"196\" height=\"56\">\n    </a>",
          "target": [
            ".brand"
          ]
        }
      ]
    },
    {
      "id": "aria-deprecated-role",
      "impact": null,
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag412",
        "EN-301-549",
        "EN-9.4.1.2"
      ],
      "description": "Ensure elements do not use deprecated roles",
      "help": "Deprecated ARIA roles must not be used",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-deprecated-role?application=axeAPI",
      "nodes": [
        {
          "any": [],
          "all": [],
          "none": [
            {
              "id": "deprecatedrole",
              "data": null,
              "relatedNodes": [],
              "impact": "minor",
              "message": "ARIA role is not deprecated"
            }
          ],
          "impact": null,
          "html": "<div class=\"tabs reveal\" id=\"postTabs\" role=\"tablist\" aria-label=\"Filter guides by topic\">",
          "target": [
            "#postTabs"
          ]
        }
      ]
    },
    {
      "id": "aria-hidden-body",
      "impact": null,
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag131",
        "wcag412",
        "EN-301-549",
        "EN-9.1.3.1",
        "EN-9.4.1.2"
      ],
      "description": "Ensure aria-hidden=\"true\" is not present on the document body.",
      "help": "aria-hidden=\"true\" must not be present on the document body",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-hidden-body?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "aria-hidden-body",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "No aria-hidden attribute is present on document body"
            }
          ],
          "all": [],
          "none": [],
          "impact": null,
          "html": "<body>",
          "target": [
            "body"
          ]
        }
      ]
    },
    {
      "id": "aria-hidden-focus",
      "impact": null,
      "tags": [
        "cat.name-role-value",
        "wcag2a",
        "wcag412",
        "TTv5",
        "TT6.a",
        "EN-301-549",
        "EN-9.4.1.2"
      ],
      "description": "Ensure aria-hidden elements are not focusable nor contain focusable elements",
      "help": "ARIA hidden element must not be focusable or contain focusable elements",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-hidden-focus?application=axeAPI",
      "nodes": [
        {
          "any": [],
          "all": [
            {
              "id": "focusable-modal-open",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "No focusable elements while a modal is open"
            },
            {
              "id": "focusable-disabled",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "No focusable elements contained within element"
            },
            {
              "id": "focusable-not-tabbable",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "No focusable elements contained within element"
            }
          ],
          "none": [],
          "impact": null,
          "html": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" data-lucide=\"heart\" aria-hidden=\"true\" class=\"lucide lucide-heart\">",
          "target": [
            ".topbar-tag > .lucide-heart[data-lucide=\"heart\"]"
          ]
        }
      ]
    },
    {
      "id": "aria-prohibited-attr",
      "impact": "serious",
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag412",
        "EN-301-549",
        "EN-9.4.1.2"
      ],
      "description": "Ensure ARIA attributes are not prohibited for an element's role",
      "help": "Elements must only use permitted ARIA attributes",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-prohibited-attr?application=axeAPI",
      "nodes": [
        {
          "any": [],
          "all": [],
          "none": [
            {
              "id": "aria-prohibited-attr",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "ARIA attribute is allowed"
            }
          ],
          "impact": null,
          "html": "<a href=\"#home\" class=\"brand\" aria-label=\"PawHaven \u2014 home\">\n      <img src=\"https://placehold.co/196x56/0E5F57/FFFFFF?text=PawHaven&amp;font=playfair+display\" alt=\"PawHaven logo\" width=\"196\" height=\"56\">\n    </a>",
          "target": [
            ".brand"
          ]
        }
      ]
    },
    {
      "id": "aria-required-attr",
      "impact": null,
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag412",
        "EN-301-549",
        "EN-9.4.1.2"
      ],
      "description": "Ensure elements with ARIA roles have all required ARIA attributes",
      "help": "Required ARIA attributes must be provided",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-required-attr?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "aria-required-attr",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "All required ARIA attributes are present"
            }
          ],
          "all": [],
          "none": [],
          "impact": null,
          "html": "<div class=\"tabs reveal\" id=\"postTabs\" role=\"tablist\" aria-label=\"Filter guides by topic\">",
          "target": [
            "#postTabs"
          ]
        }
      ]
    },
    {
      "id": "aria-required-children",
      "impact": null,
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag131",
        "EN-301-549",
        "EN-9.1.3.1"
      ],
      "description": "Ensure elements with an ARIA role that require child roles contain them",
      "help": "Certain ARIA roles must contain particular children",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-required-children?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "aria-required-children",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "Required ARIA children are present"
            }
          ],
          "all": [],
          "none": [],
          "impact": null,
          "html": "<div class=\"tabs reveal\" id=\"postTabs\" role=\"tablist\" aria-label=\"Filter guides by topic\">",
          "target": [
            "#postTabs"
          ]
        }
      ]
    },
    {
      "id": "aria-required-parent",
      "impact": null,
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag131",
        "EN-301-549",
        "EN-9.1.3.1"
      ],
      "description": "Ensure elements with an ARIA role that require parent roles are contained by them",
      "help": "Certain ARIA roles must be contained by particular parents",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-required-parent?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "aria-required-parent",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "Required ARIA parent role present"
            }
          ],
          "all": [],
          "none": [],
          "impact": null,
          "html": "<button class=\"tab active\" role=\"tab\" aria-selected=\"true\">All Posts</button>",
          "target": [
            ".active"
          ]
        }
      ]
    },
    {
      "id": "aria-roles",
      "impact": null,
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag412",
        "EN-301-549",
        "EN-9.4.1.2"
      ],
      "description": "Ensure all elements with a role attribute use a valid value",
      "help": "ARIA roles used must conform to valid values",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-roles?application=axeAPI",
      "nodes": [
        {
          "any": [],
          "all": [],
          "none": [
            {
              "id": "invalidrole",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "ARIA role is valid"
            },
            {
              "id": "abstractrole",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "Abstract roles are not used"
            },
            {
              "id": "unsupportedrole",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "ARIA role is supported"
            }
          ],
          "impact": null,
          "html": "<div class=\"tabs reveal\" id=\"postTabs\" role=\"tablist\" aria-label=\"Filter guides by topic\">",
          "target": [
            "#postTabs"
          ]
        }
      ]
    },
    {
      "id": "aria-valid-attr-value",
      "impact": null,
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag412",
        "EN-301-549",
        "EN-9.4.1.2"
      ],
      "description": "Ensure all ARIA attributes have valid values",
      "help": "ARIA attributes must conform to valid values",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-valid-attr-value?application=axeAPI",
      "nodes": [
        {
          "any": [],
          "all": [
            {
              "id": "aria-valid-attr-value",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "ARIA attribute values are valid"
            },
            {
              "id": "aria-errormessage",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "aria-errormessage exists and references elements visible to screen readers that use a supported aria-errormessage technique"
            },
            {
              "id": "aria-level",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "aria-level values are valid"
            }
          ],
          "none": [],
          "impact": null,
          "html": "<a href=\"#home\" class=\"brand\" aria-label=\"PawHaven \u2014 home\">\n      <img src=\"https://placehold.co/196x56/0E5F57/FFFFFF?text=PawHaven&amp;font=playfair+display\" alt=\"PawHaven logo\" width=\"196\" height=\"56\">\n    </a>",
          "target": [
            ".brand"
          ]
        }
      ]
    },
    {
      "id": "aria-valid-attr",
      "impact": null,
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag412",
        "EN-301-549",
        "EN-9.4.1.2"
      ],
      "description": "Ensure attributes that begin with aria- are valid ARIA attributes",
      "help": "ARIA attributes must conform to valid names",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-valid-attr?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "aria-valid-attr",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "ARIA attribute name is valid"
            }
          ],
          "all": [],
          "none": [],
          "impact": null,
          "html": "<a href=\"#home\" class=\"brand\" aria-label=\"PawHaven \u2014 home\">\n      <img src=\"https://placehold.co/196x56/0E5F57/FFFFFF?text=PawHaven&amp;font=playfair+display\" alt=\"PawHaven logo\" width=\"196\" height=\"56\">\n    </a>",
          "target": [
            ".brand"
          ]
        }
      ]
    },
    {
      "id": "autocomplete-valid",
      "impact": null,
      "tags": [
        "cat.forms",
        "wcag21aa",
        "wcag135",
        "EN-301-549",
        "EN-9.1.3.5",
        "ACT"
      ],
      "description": "Ensure the autocomplete attribute is correct and suitable for the form field",
      "help": "autocomplete attribute must be used correctly",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/autocomplete-valid?application=axeAPI",
      "nodes": [
        {
          "any": [],
          "all": [
            {
              "id": "autocomplete-valid",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "the autocomplete attribute is correctly formatted"
            }
          ],
          "none": [],
          "impact": null,
          "html": "<input id=\"petName\" type=\"text\" placeholder=\"e.g. Biscuit\" autocomplete=\"off\">",
          "target": [
            "#petName"
          ]
        }
      ]
    },
    {
      "id": "avoid-inline-spacing",
      "impact": null,
      "tags": [
        "cat.structure",
        "wcag21aa",
        "wcag1412",
        "EN-301-549",
        "EN-9.1.4.12",
        "ACT"
      ],
      "description": "Ensure that text spacing set through style attributes can be adjusted with custom stylesheets",
      "help": "Inline text spacing must be adjustable with custom stylesheets",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/avoid-inline-spacing?application=axeAPI",
      "nodes": [
        {
          "any": [],
          "all": [
            {
              "id": "important-letter-spacing",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "Letter-spacing in the style attribute is not set to !important, or meets the minimum"
            },
            {
              "id": "important-word-spacing",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "word-spacing in the style attribute is not set to !important, or meets the minimum"
            },
            {
              "id": "important-line-height",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "line-height in the style attribute is not set to !important, or meets the minimum"
            }
          ],
          "none": [],
          "impact": null,
          "html": "<div class=\"hero-media reveal done\" style=\"animation-delay:.12s\">",
          "target": [
            ".hero-media"
          ]
        }
      ]
    },
    {
      "id": "button-name",
      "impact": null,
      "tags": [
        "cat.name-role-value",
        "wcag2a",
        "wcag412",
        "section508",
        "section508.22.a",
        "TTv5",
        "TT6.a",
        "EN-301-549",
        "EN-9.4.1.2",
        "ACT"
      ],
      "description": "Ensure buttons have discernible text",
      "help": "Buttons must have discernible text",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/button-name?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "button-has-visible-text",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "Element has inner text that is visible to screen readers"
            }
          ],
          "all": [],
          "none": [],
          "impact": null,
          "html": "<button type=\"button\" class=\"pill\">Wellness Exam <span>\u00b7</span> $65</button>",
          "target": [
            ".pill[type=\"button\"]:nth-child(1)"
          ]
        }
      ]
    },
    {
      "id": "bypass",
      "impact": null,
      "tags": [
        "cat.keyboard",
        "wcag2a",
        "wcag241",
        "section508",
        "section508.22.o",
        "TTv5",
        "TT9.a",
        "EN-301-549",
        "EN-9.2.4.1"
      ],
      "description": "Ensure each page has at least one mechanism for a user to bypass navigation and jump straight to the content",
      "help": "Page must have means to bypass repeated blocks",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/bypass?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "internal-link-present",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "Valid skip link found"
            },
            {
              "id": "header-present",
              "data": null,
              "relatedNodes": [
                {
                  "html": "<h1>Everything your pet needs for a <em>lifetime</em> of good health.</h1>",
                  "target": [
                    "h1"
                  ]
                },
                {
                  "html": "<h2>One team for every chapter of their life</h2>",
                  "target": [
                    "#services > .container > .section-head.reveal > div > h2"
                  ]
                },
                {
                  "html": "<h3>Veterinary Care</h3>",
                  "target": [
                    ".service-card:nth-child(1) > h3"
                  ]
                },
                {
                  "html": "<h3>Adoption &amp; Rescue</h3>",
                  "target": [
                    ".service-card:nth-child(2) > h3"
                  ]
                },
                {
                  "html": "<h3>Training &amp; Behavior</h3>",
                  "target": [
                    ".service-card:nth-child(3) > h3"
                  ]
                },
                {
                  "html": "<h3>Grooming &amp; Wellness</h3>",
                  "target": [
                    ".service-card:nth-child(4) > h3"
                  ]
                },
                {
                  "html": "<h2>Book a visit in under a minute</h2>",
                  "target": [
                    "#book > .container > .center.section-head.reveal > div > h2"
                  ]
                },
                {
                  "html": "<h3>What do you need?</h3>",
                  "target": [
                    ".step:nth-child(1) > .step-head > h3"
                  ]
                },
                {
                  "html": "<h3>Pick a day</h3>",
                  "target": [
                    ".step:nth-child(2) > .step-head > h3"
                  ]
                },
                {
                  "html": "<h3>Pick a time</h3>",
                  "target": [
                    ".step:nth-child(3) > .step-head > h3"
                  ]
                },
                {
                  "html": "<h3>Tell us about your pet</h3>",
                  "target": [
                    ".step:nth-child(4) > .step-head > h3"
                  ]
                },
                {
                  "html": "<h3>Your appointment</h3>",
                  "target": [
                    ".book-summary > h3"
                  ]
                },
                {
                  "html": "<h2>Expert guides for every kind of pet parent</h2>",
                  "target": [
                    "#library > .container > .section-head.reveal > div > h2"
                  ]
                },
                {
                  "html": "<h3>The Golden Retriever, Explained: Health, Temperament &amp; Daily Care</h3>",
                  "target": [
                    ".post-card[role=\"button\"]:nth-child(1) > .post-body > h3"
                  ]
                },
                {
                  "html": "<h3>The Slow Blink: A Veterinarian's Guide to Reading Your Cat</h3>",
                  "target": [
                    ".post-card[role=\"button\"]:nth-child(2) > .post-body > h3"
                  ]
                },
                {
                  "html": "<h3>After Seven: How Your Pet's Needs Change in Their Senior Years</h3>",
                  "target": [
                    ".post-card[role=\"button\"]:nth-child(3) > .post-body > h3"
                  ]
                },
                {
                  "html": "<h3>The Socialization Window: What 8 to 16 Weeks Can Shape for Life</h3>",
                  "target": [
                    ".post-card[role=\"button\"]:nth-child(4) > .post-body > h3"
                  ]
                },
                {
                  "html": "<h3>How to Read a Pet Food Label (and What AAFCO Actually Means)</h3>",
                  "target": [
                    ".post-card[role=\"button\"]:nth-child(5) > .post-body > h3"
                  ]
                },
                {
                  "html": "<h3>Litter Box Problems? A Vet's Step-by-Step Troubleshooting Guide</h3>",
                  "target": [
                    ".post-card[role=\"button\"]:nth-child(6) > .post-body > h3"
                  ]
                },
                {
                  "html": "<h2>Happy tails start here</h2>",
                  "target": [
                    ".adoption-main > .section-head.reveal > div > h2"
                  ]
                },
                {
                  "html": "<h3>Ready to meet someone furry?</h3>",
                  "target": [
                    ".adoption-cta > div > h3"
                  ]
                },
                {
                  "html": "<h3>Adoption events</h3>",
                  "target": [
                    ".side-card.reveal:nth-child(1) > .side-head > h3"
                  ]
                },
                {
                  "html": "<h3>Looking for a home</h3>",
                  "target": [
                    ".side-card.reveal:nth-child(2) > .side-head > h3"
                  ]
                },
                {
                  "html": "<h3>The Weekly Wag</h3>",
                  "target": [
                    ".side-news > .side-head > h3"
                  ]
                },
                {
                  "html": "<h2>Answers, before you even ask</h2>",
                  "target": [
                    ".faq-wrap > .center.section-head.reveal > div > h2"
                  ]
                },
                {
                  "html": "<h2>Whatever your pet needs next, we're ready.</h2>",
                  "target": [
                    ".cta-banner > h2"
                  ]
                },
                {
                  "html": "<h4>Explore</h4>",
                  "target": [
                    "nav[aria-label=\"Explore\"] > h4"
                  ]
                },
                {
                  "html": "<h4>Services</h4>",
                  "target": [
                    "nav[aria-label=\"Services\"] > h4"
                  ]
                },
                {
                  "html": "<h4>Visit us</h4>",
                  "target": [
                    ".footer-contact > h4"
                  ]
                }
              ],
              "impact": "serious",
              "message": "Page has a heading"
            },
            {
              "id": "landmark",
              "data": null,
              "relatedNodes": [
                {
                  "html": "<main id=\"main\">",
                  "target": [
                    "#main"
                  ]
                }
              ],
              "impact": "serious",
              "message": "Page has a landmark region"
            }
          ],
          "all": [],
          "none": [],
          "impact": null,
          "html": "<html lang=\"en\">",
          "target": [
            "html"
          ]
        }
      ]
    },
    {
      "id": "color-contrast",
      "impact": "serious",
      "tags": [
        "cat.color",
        "wcag2aa",
        "wcag143",
        "TTv5",
        "TT13.c",
        "EN-301-549",
        "EN-9.1.4.3",
        "ACT"
      ],
      "description": "Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds",
      "help": "Elements must meet minimum color contrast ratio thresholds",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/color-contrast?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "color-contrast",
              "data": {
                "fgColor": "#dae1e1",
                "bgColor": "#0b3a35",
                "contrastRatio": 9.47,
                "fontSize": "9.8pt (13.12px)",
                "fontWeight": "normal",
                "messageKey": null,
                "expectedContrastRatio": "4.5:1",
                "shadowColor": null
              },
              "relatedNodes": [],
              "impact": "serious",
              "message": "Element has sufficient color contrast of 9.47"
            }
          ],
          "all": [],
          "none": [],
          "impact": null,
          "html": "<p class=\"topbar-tag\">",
          "target": [
            ".topbar-tag"
          ]
        }
      ]
    },
    {
      "id": "document-title",
      "impact": null,
      "tags": [
        "cat.text-alternatives",
        "wcag2a",
        "wcag242",
        "TTv5",
        "TT12.a",
        "EN-301-549",
        "EN-9.2.4.2",
        "ACT"
      ],
      "description": "Ensure each HTML document contains a non-empty <title> element",
      "help": "Documents must have <title> element to aid in navigation",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/document-title?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "doc-has-title",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "Document has a non-empty <title> element"
            }
          ],
          "all": [],
          "none": [],
          "impact": null,
          "html": "<html lang=\"en\">",
          "target": [
            "html"
          ]
        }
      ]
    },
    {
      "id": "duplicate-id-aria",
      "impact": null,
      "tags": [
        "cat.parsing",
        "wcag2a",
        "wcag412",
        "EN-301-549",
        "EN-9.4.1.2"
      ],
      "description": "Ensure every id attribute value used in ARIA and in labels is unique",
      "help": "IDs used in ARIA and labels must be unique",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/duplicate-id-aria?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "duplicate-id-aria",
              "data": "mainNav",
              "relatedNodes": [],
              "impact": "critical",
              "message": "Document has no elements referenced with ARIA or labels that share the same id attribute"
            }
          ],
          "all": [],
          "none": [],
          "impact": null,
          "html": "<nav class=\"main-nav\" id=\"mainNav\" aria-label=\"Primary\">",
          "target": [
            "#mainNav"
          ]
        }
      ]
    },
    {
      "id": "form-field-multiple-labels",
      "impact": null,
      "tags": [
        "cat.forms",
        "wcag2a",
        "wcag332",
        "TTv5",
        "TT5.c",
        "EN-301-549",
        "EN-9.3.3.2"
      ],
      "description": "Ensure form field does not have multiple label elements",
      "help": "Form field must not have multiple label elements",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/form-field-multiple-labels?application=axeAPI",
      "nodes": [
        {
          "any": [],
          "all": [],
          "none": [
            {
              "id": "multiple-label",
              "data": null,
              "relatedNodes": [
                {
                  "html": "<label for=\"petName\">Pet's name</label>",
                  "target": [
                    "label[for=\"petName\"]"
                  ]
                }
              ],
              "impact": "moderate",
              "message": "Form field does not have multiple label elements"
            }
          ],
          "impact": null,
          "html": "<input id=\"petName\" type=\"text\" placeholder=\"e.g. Biscuit\" autocomplete=\"off\">",
          "target": [
            "#petName"
          ]
        }
      ]
    },
    {
      "id": "html-has-lang",
      "impact": null,
      "tags": [
        "cat.language",
        "wcag2a",
        "wcag311",
        "TTv5",
        "TT11.a",
        "EN-301-549",
        "EN-9.3.1.1",
        "ACT"
      ],
      "description": "Ensure every HTML document has a lang attribute",
      "help": "<html> element must have a lang attribute",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/html-has-lang?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "has-lang",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "The <html> element has a lang attribute"
            }
          ],
          "all": [],
          "none": [],
          "impact": null,
          "html": "<html lang=\"en\">",
          "target": [
            "html"
          ]
        }
      ]
    },
    {
      "id": "html-lang-valid",
      "impact": null,
      "tags": [
        "cat.language",
        "wcag2a",
        "wcag311",
        "TTv5",
        "TT11.a",
        "EN-301-549",
        "EN-9.3.1.1",
        "ACT"
      ],
      "description": "Ensure the lang attribute of the <html> element has a valid value",
      "help": "<html> element must have a valid value for the lang attribute",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/html-lang-valid?application=axeAPI",
      "nodes": [
        {
          "any": [],
          "all": [],
          "none": [
            {
              "id": "valid-lang",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "Value of lang attribute is included in the list of valid languages"
            }
          ],
          "impact": null,
          "html": "<html lang=\"en\">",
          "target": [
            "html"
          ]
        }
      ]
    },
    {
      "id": "image-alt",
      "impact": null,
      "tags": [
        "cat.text-alternatives",
        "wcag2a",
        "wcag111",
        "section508",
        "section508.22.a",
        "TTv5",
        "TT7.a",
        "TT7.b",
        "EN-301-549",
        "EN-9.1.1.1",
        "ACT"
      ],
      "description": "Ensure <img> elements have alternative text or a role of none or presentation",
      "help": "Images must have alternative text",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/image-alt?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "has-alt",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "Element has an alt attribute"
            }
          ],
          "all": [],
          "none": [
            {
              "id": "alt-space-value",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "Element has a valid alt attribute value"
            }
          ],
          "impact": null,
          "html": "<img src=\"https://placehold.co/196x56/0E5F57/FFFFFF?text=PawHaven&amp;font=playfair+display\" alt=\"PawHaven logo\" width=\"196\" height=\"56\">",
          "target": [
            ".brand > img[alt=\"PawHaven logo\"][width=\"196\"][height=\"56\"]"
          ]
        }
      ]
    },
    {
      "id": "label",
      "impact": null,
      "tags": [
        "cat.forms",
        "wcag2a",
        "wcag412",
        "section508",
        "section508.22.n",
        "TTv5",
        "TT5.c",
        "EN-301-549",
        "EN-9.4.1.2",
        "ACT"
      ],
      "description": "Ensure every form element has a label",
      "help": "Form elements must have labels",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/label?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "explicit-label",
              "data": null,
              "relatedNodes": [
                {
                  "html": "<label for=\"petName\">Pet's name</label>",
                  "target": [
                    "label[for=\"petName\"]"
                  ]
                }
              ],
              "impact": "critical",
              "message": "Element has an explicit <label>"
            },
            {
              "id": "non-empty-placeholder",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "Element has a placeholder attribute"
            }
          ],
          "all": [],
          "none": [
            {
              "id": "hidden-explicit-label",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "Form element has a visible explicit <label>"
            }
          ],
          "impact": null,
          "html": "<input id=\"petName\" type=\"text\" placeholder=\"e.g. Biscuit\" autocomplete=\"off\">",
          "target": [
            "#petName"
          ]
        }
      ]
    },
    {
      "id": "link-name",
      "impact": null,
      "tags": [
        "cat.name-role-value",
        "wcag2a",
        "wcag244",
        "wcag412",
        "section508",
        "section508.22.a",
        "TTv5",
        "TT6.a",
        "EN-301-549",
        "EN-9.2.4.4",
        "EN-9.4.1.2",
        "ACT"
      ],
      "description": "Ensure links have discernible text",
      "help": "Links must have discernible text",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/link-name?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "has-visible-text",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "Element has text that is visible to screen readers"
            }
          ],
          "all": [],
          "none": [
            {
              "id": "focusable-no-name",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "Element is not in tab order or has accessible text"
            }
          ],
          "impact": null,
          "html": "<a class=\"skip\" href=\"#main\">Skip to content</a>",
          "target": [
            ".skip"
          ]
        }
      ]
    },
    {
      "id": "list",
      "impact": null,
      "tags": [
        "cat.structure",
        "wcag2a",
        "wcag131",
        "EN-301-549",
        "EN-9.1.3.1"
      ],
      "description": "Ensure that lists are structured correctly",
      "help": "<ul> and <ol> must only directly contain <li>, <script> or <template> elements",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/list?application=axeAPI",
      "nodes": [
        {
          "any": [],
          "all": [],
          "none": [
            {
              "id": "only-listitems",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "List element only has direct children that are allowed inside <li> elements"
            }
          ],
          "impact": null,
          "html": "<ul class=\"sum-next\">",
          "target": [
            ".sum-next"
          ]
        }
      ]
    },
    {
      "id": "listitem",
      "impact": null,
      "tags": [
        "cat.structure",
        "wcag2a",
        "wcag131",
        "EN-301-549",
        "EN-9.1.3.1"
      ],
      "description": "Ensure <li> elements are used semantically",
      "help": "<li> elements must be contained in a <ul> or <ol>",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/listitem?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "listitem",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "List item has a <ul>, <ol> or role=\"list\" parent element"
            }
          ],
          "all": [],
          "none": [],
          "impact": null,
          "html": "<li>",
          "target": [
            ".sum-next > li:nth-child(1)"
          ]
        }
      ]
    },
    {
      "id": "meta-viewport",
      "impact": null,
      "tags": [
        "cat.sensory-and-visual-cues",
        "wcag2aa",
        "wcag144",
        "EN-301-549",
        "EN-9.1.4.4",
        "ACT"
      ],
      "description": "Ensure <meta name=\"viewport\"> does not disable text scaling and zooming",
      "help": "Zooming and scaling must not be disabled",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/meta-viewport?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "meta-viewport",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "<meta> tag does not disable zooming on mobile devices"
            }
          ],
          "all": [],
          "none": [],
          "impact": null,
          "html": "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">",
          "target": [
            "meta[name=\"viewport\"]"
          ]
        }
      ]
    },
    {
      "id": "nested-interactive",
      "impact": null,
      "tags": [
        "cat.keyboard",
        "wcag2a",
        "wcag412",
        "TTv5",
        "TT6.a",
        "EN-301-549",
        "EN-9.4.1.2"
      ],
      "description": "Ensure interactive controls are not nested as they are not always announced by screen readers or can cause focus problems for assistive technologies",
      "help": "Interactive controls must not be nested",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/nested-interactive?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "no-focusable-content",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "Element does not have focusable descendants"
            }
          ],
          "all": [],
          "none": [],
          "impact": null,
          "html": "<img src=\"https://placehold.co/196x56/0E5F57/FFFFFF?text=PawHaven&amp;font=playfair+display\" alt=\"PawHaven logo\" width=\"196\" height=\"56\">",
          "target": [
            ".brand > img[alt=\"PawHaven logo\"][width=\"196\"][height=\"56\"]"
          ]
        }
      ]
    },
    {
      "id": "scrollable-region-focusable",
      "impact": null,
      "tags": [
        "cat.keyboard",
        "wcag2a",
        "wcag211",
        "wcag213",
        "TTv5",
        "TT4.a",
        "EN-301-549",
        "EN-9.2.1.1",
        "EN-9.2.1.3"
      ],
      "description": "Ensure elements that have scrollable content are accessible by keyboard",
      "help": "Scrollable region must have keyboard access",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/scrollable-region-focusable?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "focusable-content",
              "data": null,
              "relatedNodes": [],
              "impact": "serious",
              "message": "Element contains focusable elements"
            }
          ],
          "all": [],
          "none": [],
          "impact": null,
          "html": "<div class=\"modal-panel\">",
          "target": [
            ".modal-panel"
          ]
        }
      ]
    },
    {
      "id": "select-name",
      "impact": null,
      "tags": [
        "cat.forms",
        "wcag2a",
        "wcag412",
        "section508",
        "section508.22.n",
        "TTv5",
        "TT5.c",
        "EN-301-549",
        "EN-9.4.1.2",
        "ACT"
      ],
      "description": "Ensure select element has an accessible name",
      "help": "Select element must have an accessible name",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/select-name?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "explicit-label",
              "data": null,
              "relatedNodes": [
                {
                  "html": "<label for=\"petType\">Pet type</label>",
                  "target": [
                    "label[for=\"petType\"]"
                  ]
                }
              ],
              "impact": "critical",
              "message": "Element has an explicit <label>"
            }
          ],
          "all": [],
          "none": [
            {
              "id": "hidden-explicit-label",
              "data": null,
              "relatedNodes": [],
              "impact": "critical",
              "message": "Form element has a visible explicit <label>"
            }
          ],
          "impact": null,
          "html": "<select id=\"petType\"><option>Dog</option><option>Cat</option><option>Rabbit</option><option>Bird</option><option>Other</option></select>",
          "target": [
            "#petType"
          ]
        }
      ]
    },
    {
      "id": "target-size",
      "impact": null,
      "tags": [
        "cat.sensory-and-visual-cues",
        "wcag22aa",
        "wcag258"
      ],
      "description": "Ensure touch targets have sufficient size and space",
      "help": "All touch targets must be 24px large, or leave sufficient space",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/target-size?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "target-size",
              "data": {
                "minSize": 24,
                "width": 151.5,
                "height": 45.6
              },
              "relatedNodes": [],
              "impact": "serious",
              "message": "Control has sufficient size (151.5px by 45.6px, should be at least 24px by 24px)"
            },
            {
              "id": "target-offset",
              "data": {
                "closestOffset": 24,
                "minOffset": 24
              },
              "relatedNodes": [],
              "impact": "serious",
              "message": "Target has sufficient space from its closest neighbors. Safe clickable space has a diameter of 24px which is at least 24px."
            }
          ],
          "all": [],
          "none": [],
          "impact": null,
          "html": "<a class=\"skip\" href=\"#main\">Skip to content</a>",
          "target": [
            ".skip"
          ]
        }
      ]
    }
  ],
  "incomplete": [
    {
      "id": "color-contrast",
      "impact": "serious",
      "tags": [
        "cat.color",
        "wcag2aa",
        "wcag143",
        "TTv5",
        "TT13.c",
        "EN-301-549",
        "EN-9.1.4.3",
        "ACT"
      ],
      "description": "Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds",
      "help": "Elements must meet minimum color contrast ratio thresholds",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/color-contrast?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "color-contrast",
              "data": {
                "fontSize": "9.4pt (12.48px)",
                "fontWeight": "bold",
                "messageKey": "pseudoContent",
                "expectedContrastRatio": "4.5:1"
              },
              "relatedNodes": [
                {
                  "html": "<section class=\"hero\" id=\"home\">",
                  "target": [
                    "#home"
                  ]
                }
              ],
              "impact": "serious",
              "message": "Element's background color could not be determined due to a pseudo element"
            }
          ],
          "all": [],
          "none": [],
          "impact": "serious",
          "html": "<p class=\"eyebrow\">Veterinary care \u00b7 Adoption \u00b7 Training \u2014 Portland, OR</p>",
          "target": [
            ".hero-copy > .eyebrow"
          ],
          "failureSummary": "Fix any of the following:\n  Element's background color could not be determined due to a pseudo element"
        }
      ]
    }
  ],
  "violations": [
    {
      "id": "aria-prohibited-attr",
      "impact": "serious",
      "tags": [
        "cat.aria",
        "wcag2a",
        "wcag412",
        "EN-301-549",
        "EN-9.4.1.2"
      ],
      "description": "Ensure ARIA attributes are not prohibited for an element's role",
      "help": "Elements must only use permitted ARIA attributes",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/aria-prohibited-attr?application=axeAPI",
      "nodes": [
        {
          "any": [],
          "all": [],
          "none": [
            {
              "id": "aria-prohibited-attr",
              "data": {
                "role": null,
                "nodeName": "span",
                "messageKey": "noRoleSingular",
                "prohibited": [
                  "aria-label"
                ]
              },
              "relatedNodes": [],
              "impact": "serious",
              "message": "aria-label attribute cannot be used on a span with no valid role attribute."
            }
          ],
          "impact": "serious",
          "html": "<span class=\"stars\" aria-label=\"Rated 4.9 out of 5\">",
          "target": [
            "span[aria-label=\"Rated 4.9 out of 5\"]"
          ],
          "failureSummary": "Fix all of the following:\n  aria-label attribute cannot be used on a span with no valid role attribute."
        },
        {
          "any": [],
          "all": [],
          "none": [
            {
              "id": "aria-prohibited-attr",
              "data": {
                "role": null,
                "nodeName": "span",
                "messageKey": "noRoleSingular",
                "prohibited": [
                  "aria-label"
                ]
              },
              "relatedNodes": [],
              "impact": "serious",
              "message": "aria-label attribute cannot be used on a span with no valid role attribute."
            }
          ],
          "impact": "serious",
          "html": "<span class=\"stars\" aria-label=\"5 out of 5 stars\">",
          "target": [
            ".story-card:nth-child(1) > .story-body > .story-foot > .stars[aria-label=\"5 out of 5 stars\"]"
          ],
          "failureSummary": "Fix all of the following:\n  aria-label attribute cannot be used on a span with no valid role attribute."
        },
        {
          "any": [],
          "all": [],
          "none": [
            {
              "id": "aria-prohibited-attr",
              "data": {
                "role": null,
                "nodeName": "span",
                "messageKey": "noRoleSingular",
                "prohibited": [
                  "aria-label"
                ]
              },
              "relatedNodes": [],
              "impact": "serious",
              "message": "aria-label attribute cannot be used on a span with no valid role attribute."
            }
          ],
          "impact": "serious",
          "html": "<span class=\"stars\" aria-label=\"5 out of 5 stars\">",
          "target": [
            ".story-card:nth-child(2) > .story-body > .story-foot > .stars[aria-label=\"5 out of 5 stars\"]"
          ],
          "failureSummary": "Fix all of the following:\n  aria-label attribute cannot be used on a span with no valid role attribute."
        },
        {
          "any": [],
          "all": [],
          "none": [
            {
              "id": "aria-prohibited-attr",
              "data": {
                "role": null,
                "nodeName": "span",
                "messageKey": "noRoleSingular",
                "prohibited": [
                  "aria-label"
                ]
              },
              "relatedNodes": [],
              "impact": "serious",
              "message": "aria-label attribute cannot be used on a span with no valid role attribute."
            }
          ],
          "impact": "serious",
          "html": "<span class=\"stars\" aria-label=\"5 out of 5 stars\">",
          "target": [
            ".story-card:nth-child(3) > .story-body > .story-foot > .stars[aria-label=\"5 out of 5 stars\"]"
          ],
          "failureSummary": "Fix all of the following:\n  aria-label attribute cannot be used on a span with no valid role attribute."
        }
      ]
    },
    {
      "id": "color-contrast",
      "impact": "serious",
      "tags": [
        "cat.color",
        "wcag2aa",
        "wcag143",
        "TTv5",
        "TT13.c",
        "EN-301-549",
        "EN-9.1.4.3",
        "ACT"
      ],
      "description": "Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds",
      "help": "Elements must meet minimum color contrast ratio thresholds",
      "helpUrl": "https://dequeuniversity.com/rules/axe/4.10/color-contrast?application=axeAPI",
      "nodes": [
        {
          "any": [
            {
              "id": "color-contrast",
              "data": {
                "fgColor": "#1c2b27",
                "bgColor": "#0e5f57",
                "contrastRatio": 1.96,
                "fontSize": "11.2pt (14.88px)",
                "fontWeight": "bold",
                "messageKey": null,
                "expectedContrastRatio": "4.5:1",
                "shadowColor": null
              },
              "relatedNodes": [
                {
                  "html": "<a href=\"#book\" class=\"btn btn-primary btn-sm nav-cta\">Book Appointment</a>",
                  "target": [
                    ".btn-sm"
                  ]
                }
              ],
              "impact": "serious",
              "message": "Element has insufficient color contrast of 1.96 (foreground color: #1c2b27, background color: #0e5f57, font size: 11.2pt (14.88px), font weight: bold). Expected contrast ratio of 4.5:1"
            }
          ],
          "all": [],
          "none": [],
          "impact": "serious",
          "html": "<a href=\"#book\" class=\"btn btn-primary btn-sm nav-cta\">Book Appointment</a>",
          "target": [
            ".btn-sm"
          ],
          "failureSummary": "Fix any of the following:\n  Element has insufficient color contrast of 1.96 (foreground color: #1c2b27, background color: #0e5f57, font size: 11.2pt (14.88px), font weight: bold). Expected contrast ratio of 4.5:1"
        },
        {
          "any": [
            {
              "id": "color-contrast",
              "data": {
                "fgColor": "#7e8583",
                "bgColor": "#14211e",
                "contrastRatio": 4.39,
                "fontSize": "10.2pt (13.6px)",
                "fontWeight": "normal",
                "messageKey": null,
                "expectedContrastRatio": "4.5:1",
                "shadowColor": null
              },
              "relatedNodes": [
                {
                  "html": "<footer class=\"site-footer\" id=\"contact\">",
                  "target": [
                    "#contact"
                  ]
                }
              ],
              "impact": "serious",
              "message": "Element has insufficient color contrast of 4.39 (foreground color: #7e8583, background color: #14211e, font size: 10.2pt (13.6px), font weight: normal). Expected contrast ratio of 4.5:1"
            }
          ],
          "all": [],
          "none": [],
          "impact": "serious",
          "html": "<p>\u00a9 <span id=\"year\">2026</span> PawHaven Pet Care, LLC. All rights reserved.</p>",
          "target": [
            ".footer-bottom > p"
          ],
          "failureSummary": "Fix any of the following:\n  Element has insufficient color contrast of 4.39 (foreground color: #7e8583, background color: #14211e, font size: 10.2pt (13.6px), font weight: normal). Expected contrast ratio of 4.5:1"
        },
        {
          "any": [
            {
              "id": "color-contrast",
              "data": {
                "fgColor": "#7e8583",
                "bgColor": "#14211e",
                "contrastRatio": 4.39,
                "fontSize": "10.2pt (13.6px)",
                "fontWeight": "normal",
                "messageKey": null,
                "expectedContrastRatio": "4.5:1",
                "shadowColor": null
              },
              "relatedNodes": [
                {
                  "html": "<footer class=\"site-footer\" id=\"contact\">",
                  "target": [
                    "#contact"
                  ]
                }
              ],
              "impact": "serious",
              "message": "Element has insufficient color contrast of 4.39 (foreground color: #7e8583, background color: #14211e, font size: 10.2pt (13.6px), font weight: normal). Expected contrast ratio of 4.5:1"
            }
          ],
          "all": [],
          "none": [],
          "impact": "serious",
          "html": "<span id=\"year\">2026</span>",
          "target": [
            "#year"
          ],
          "failureSummary": "Fix any of the following:\n  Element has insufficient color contrast of 4.39 (foreground color: #7e8583, background color: #14211e, font size: 10.2pt (13.6px), font weight: normal). Expected contrast ratio of 4.5:1"
        }
      ]
    }
  ],
  "coverage": {
    "contract": "main-document-vertical-scroll",
    "complete": true,
    "positions": [
      {
        "y": 0,
        "height": 8171
      },
      {
        "y": 576,
        "height": 8171
      },
      {
        "y": 1152,
        "height": 8171
      },
      {
        "y": 1728,
        "height": 8171
      },
      {
        "y": 2304,
        "height": 8171
      },
      {
        "y": 2880,
        "height": 8171
      },
      {
        "y": 3456,
        "height": 8171
      },
      {
        "y": 4032,
        "height": 8171
      },
      {
        "y": 4608,
        "height": 8171
      },
      {
        "y": 5184,
        "height": 8171
      },
      {
        "y": 5760,
        "height": 8171
      },
      {
        "y": 6336,
        "height": 8171
      },
      {
        "y": 6912,
        "height": 8171
      },
      {
        "y": 7451,
        "height": 8171
      }
    ],
    "scans": 15,
    "max_states": 512,
    "settle_ms": 5000,
    "page_timeout_seconds": 150,
    "layout_stability": "consecutive 100ms size samples within one CSS pixel",
    "animation_settling": "finite animations present when scroll resources are ready finish or are cancelled",
    "interactive_states": "not exercised",
    "horizontal_scroll": "not exercised"
  }
}
System Prompt
You are a lead web developer at a top digital agency, tasked with creating a one-page website for a new client based on the given specifications, delivered as an HTML file. First non-whitespace char '<', last non-whitespace char '>'. Use the following services to generate placeholder images where needed:
- placehold.co (text): https://placehold.co/[{w}x{h}|{size}][/{bg-color}/{text-color}]?text={text}&font=[lato|lora|montserrat|noto sans|open sans|oswald|playfair display|poppins|pt sans|raleway|roboto|source sans|source sans pro]
- picsum.photos (photos): https://picsum.photos/[{w}/{h}|{size}]?[grayscale][&blur={1-10}]
- pravatar.cc (avatars): https://i.pravatar.cc/{size}?u={identifier}
Choose sizes appropriate to layout.
User Prompt
Create a **complete, polished, production-quality** primary web page for a new client in the "Pets" sector.
Your goal is to generate the full HTML code for a page that is not just functional but also visually compelling, content-rich, and feels like a finished product ready for launch.

**Client & Category:**
- Industry: "Pets"
- Description: Pet care, adoption, veterinary resources, training, and animal rescue information.

**Your Creative Task:**
1.  **Invent:** Create a unique, professional-sounding site name and a strong tagline fitting the "Pets" category.
2.  **Define Page:** Determine the most effective primary page type (e.g., homepage, service landing page, category portal) to showcase this fictional entity.
3.  **Design:** Develop an opinionated, modern, and professional layout. Make distinct choices about structure and flow.

**Content & Structure Requirements (Deliver a COMPLETE page):**
-   **Overall:** The final page must feel substantial and complete, with realistic amounts of text (multiple paragraphs per section where appropriate, avoid single sentences), well-integrated placeholder images, and logical flow. It should look like a real website a business would proudly use.
-   **HEADER:** Include the invented site name, tagline, a logo placeholder image, and a primary navigation bar. Ensure the navigation has **at least 5-7 clearly defined, relevant links** including: "Pet Care", "Contact", "Blog".
-   **MAIN CONTENT:** Structure this area with **at least 3-4 distinct, well-developed sections**.
    -   Address key topics relevant to the "Pets" category. Consider themes similar to: "Breed Guides", "Senior Pet Care", "Training Tips".
    -   **Content Depth:** Populate each section with **substantial, realistic text** (multiple sentences/paragraphs). Use authentic industry language and terminology like: "socialization", "wellness exam", "breed characteristics".
    -   **Visuals:** Integrate relevant placeholder images logically within the content sections.
    -   **Calls to Action:** Include clear and contextually relevant CTAs. Use strong verbs similar to: "Make Appointment", "Read Guide", "Learn More".
-   **ENGAGEMENT (Recommended):** Strongly consider incorporating **one meaningful interactive element** that would genuinely benefit a user in the "Pets" sector. Ideas similar but not limited to: "appointment scheduler".
-   **SIDEBAR (Optional):** If your design includes a sidebar, populate it with **useful, relevant content**. Ideas: "adoption success stories", "event calendar", "product reviews".
-   **FOOTER:** Include a professional footer with invented contact details, copyright (current year), social media links, and standard links (Privacy, Terms).
-   **MODERN WEB PATTERNS:** Include modern web patterns like testimonial cards, feature grids, or FAQ accordions where appropriate.