/* Furever Fixed.
   Palette and type are the NPO's own corporate identity: #3DBB93 and black,
   Good Dog for display and Lato Bold for supporting headings. Do not swap these
   for something "nicer" - they match the logo, the stickers and the Facebook
   artwork, and the site is one piece of that set.

   Every font is self-hosted. The CSP sets font-src 'self', so a Google Fonts
   link would be blocked - which is deliberate, not an obstacle to work around.
   Good Dog is freeware from Fonthead Design; its readme is kept alongside it in
   fonts/GoodDog-licence.txt because redistributing it is conditional on that. */

@font-face {
  font-family: "Good Dog";
  src: url("/static/fonts/good-dog.ttf") format("truetype");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Lato";
  src: url("/static/fonts/lato-400.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Lato";
  src: url("/static/fonts/lato-700.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}
@font-face {
  font-family: "Lato";
  src: url("/static/fonts/lato-900.woff2") format("woff2");
  font-weight: 900;
  font-display: swap;
}
@font-face {
  font-family: "Roboto";
  src: url("/static/fonts/roboto-400.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Roboto";
  src: url("/static/fonts/roboto-500.woff2") format("woff2");
  font-weight: 500;
  font-display: swap;
}

:root {
  --mint: #3dbb93;
  --mint-dark: #2e9a77;
  --mint-wash: #eaf7f2;
  --ink: #1d1d1d;
  /* #7A7A7A is the kit's --e-global-color-text. Body copy is this, not near-black. */
  --ink-soft: #7a7a7a;
  --paper: #ffffff;
  --shell: #f6faf8;
  --line: #e4ece9;

  --radius: 18px;
  --shadow: 0 2px 4px rgba(29, 29, 29, .04), 0 10px 30px rgba(29, 29, 29, .07);
  /* 1140px is Elementor's container-max-width on this site. */
  --wrap: 1140px;

  /* Three faces, as the kit defines them: Good Dog for the script moments,
     Lato 700 for headings, Roboto for body copy. */
  --display: "Good Dog", "Comic Sans MS", cursive;
  --heading: "Lato", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  --sans: "Roboto", -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  /* Column layout with main flexed so a short page - an empty Events list, the
     404 - still puts the footer on the bottom of the screen instead of halfway
     up it. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  color: var(--ink-soft);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}

/* Good Dog is an all-caps-flavoured display face and sets small. It needs the
   size bump and the looser tracking or it reads as a scribble. */
h1, h2 {
  font-family: var(--heading);
  font-weight: 700;
  line-height: 1.2;
  margin: 0 0 .5em;
  color: var(--mint);
}
h1 { font-size: clamp(1.9rem, 4.5vw, 2.6rem); }
h2 { font-size: clamp(1.6rem, 3.4vw, 2.1rem); }
h3 {
  font-family: var(--heading); font-weight: 700;
  font-size: 1.1rem; line-height: 1.3; margin: 0 0 .5em;
}
/* Good Dog is kept for the script moments the original set as banner images. */
.display { font-family: var(--display); font-weight: 400; color: var(--ink); }
.mint { color: var(--mint); }
p { margin: 0 0 1em; }
a { color: var(--mint-dark); }
a:hover { color: var(--ink); }
img { max-width: 100%; display: block; }

/* Takes up the slack so the footer lands on the bottom of a short page. */
main { flex: 1 0 auto; }

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 20px; }
.narrow { max-width: 700px; }
.center { text-align: center; }
.center-block { margin-inline: auto; }
.mt { margin-top: 3rem; }
.mt-sm { margin-top: .75rem; }

.skip { position: absolute; left: -9999px; background: var(--mint); color: #fff;
        padding: 10px 16px; border-radius: 0 0 8px 0; }
.skip:focus { left: 0; top: 0; z-index: 20; }

/* ---------- header ---------- */

/* The original's header, read out of its Elementor settings rather than eyeballed:
   a mint-to-cyan gradient block with a *negative* clouds shape divider along its
   bottom edge. Negative means the shape is the inverse - white clouds bulging up
   into the gradient, melting into the white page below. clouds.svg carries that
   inverted path with Elementor's own `fill: #fff`.

   One shape stretched across the full width, never tiled: the original sets the
   svg to `width: calc(100% + 1.3px)`, which gives a handful of big clouds. A
   repeating tile gives lots of small ones, which is what was wrong before.

   The filename carries what the shape *is*, and changes when the shape changes.
   url() inside this stylesheet gets no `?v=`, so a new fill in the same filename
   is invisible behind Cloudflare's 4-hour cache - which is exactly how a
   reverted change stayed on screen for hours. Rename, do not edit in place.

   The gradient is the background and the clouds are white shapes sitting on it.
   Getting the balance right means knowing that the shape is only white across
   its bottom ~75% - the top quarter of its own box is transparent sky. So the
   layer is sized to **50% of the header**, which puts the white at about a
   third of it. At 100% the white swallowed three quarters of the header and the
   gradient survived as a strip along the top, which read as the wrong way
   round. Measure it by compositing the two layers onto a canvas and counting
   white pixels - eyeballing a screenshot got this wrong twice. */
.site-head {
  padding: 40px 0 86px;
  background-color: #29c0f2;
  background-image: url("/static/img/clouds-white.svg"),
                    linear-gradient(180deg, #00ffb9 0%, #29c0f2 100%);
  background-repeat: no-repeat, no-repeat;
  background-position: bottom center, top center;
  background-size: calc(100% + 1.3px) 50%, 100% 100%;
}
.head-inner {
  display: grid; grid-template-columns: auto 1fr auto;
  align-items: center; gap: 16px;
}
.brand-mark { justify-self: start; }
.brand-mark img { width: clamp(64px, 9vw, 112px); height: auto; }
.brand { justify-self: center; }
.brand img { width: clamp(230px, 40vw, 440px); height: auto; }
/* Donate sits above the three social buttons, as asked. */
.head-side {
  justify-self: end;
  display: flex; flex-direction: column; align-items: center; gap: 10px;
}
.socials { display: flex; align-items: center; gap: 10px; }

.social {
  width: 36px; height: 36px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--mint); color: #fff; text-decoration: none;
  font-size: 1rem; line-height: 1;
}
/* Each channel in its own brand colour, which is what the old site did too.
   The hover shade is a second explicit colour rather than filter: brightness(),
   which a running animation on the same element makes unreliable. */
.social-email    { background: #ea4335; }
.social-whatsapp { background: #25d366; }
.social-facebook { background: #3b5998; }
.social-email:hover,    .social-email:focus-visible    { background: #c5281a; }
.social-whatsapp:hover, .social-whatsapp:focus-visible { background: #1da851; }
.social-facebook:hover, .social-facebook:focus-visible { background: #2c4478; }
.social:hover, .social:focus-visible { color: #fff; }

/* A small bounce on hover, on top of the shade. Motion is opt-in: anyone who
   has asked for less gets the colour change only. */
@media (prefers-reduced-motion: no-preference) {
  .social { transition: background-color .15s ease; }
  .social:hover, .social:focus-visible { animation: social-bounce .45s ease; }
}
@keyframes social-bounce {
  0%   { transform: translateY(0); }
  35%  { transform: translateY(-7px); }
  60%  { transform: translateY(0); }
  80%  { transform: translateY(-3px); }
  100% { transform: translateY(0); }
}
.social svg { width: 18px; height: 18px; fill: currentColor; }

.site-nav {
  grid-column: 1 / -1; display: flex; justify-content: center;
  gap: 4px; flex-wrap: wrap; padding: 6px 0 0;
}
.site-nav a {
  font-family: var(--sans); font-weight: 700; font-size: .95rem;
  text-decoration: none; color: var(--ink);
  padding: 8px 16px; border-radius: 999px;
}
.site-nav a:hover, .site-nav a[aria-current="page"] { background: var(--mint-wash); color: var(--mint-dark); }

/* ---------- bands ---------- */

/* padding-block, not the padding shorthand: `section class="wrap band"` is a
   common shape here, and a shorthand would zero the gutter .wrap sets. */
.band { padding-block: clamp(2.5rem, 6vw, 4.5rem); }
/* The first band starts where the clouds finish. Its usual top padding leaves a
   white gap under them and the page reads as two disconnected pieces. */
main > .band:first-child { padding-block-start: 1.2rem; }
.band-shell { background: var(--shell); }
.band-head { display: flex; align-items: baseline; justify-content: space-between;
             gap: 16px; flex-wrap: wrap; }
.more { font-family: var(--sans); font-weight: 700; text-decoration: none;
        font-size: .95rem; white-space: nowrap; }
.lede { font-size: 1.1rem; color: var(--ink-soft); max-width: 66ch; white-space: pre-line; }
.eyebrow { font-family: var(--sans); font-weight: 900; text-transform: uppercase;
           letter-spacing: .14em; font-size: .75rem; color: var(--mint);
           margin: 0 0 .6rem; }

/* ---------- service cards ---------- */
/* The original shows each service as one piece of artwork with the caption baked
   in, rounded 200px on every corner and given a heavy even shadow, shrinking to
   80% on hover. All four of those numbers are lifted from the Elementor CSS -
   they are the design, not a starting point. The alt text carries the same
   wording as the artwork so the caption is not lost to a screen reader. */

.services {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
  margin-top: 1.2rem;
  align-items: start;
}
/* The services band is deliberately tighter than the others: the whole point is
   that the three tiles and their captions land on one screen. */
.band-services { padding-block: 2.2rem; }
.band-services .lede { margin-bottom: .5rem; }
.service { text-align: center; display: grid; justify-items: center; }
.service img {
  /* Capped against the viewport height so all three tiles and their captions
     fit on one screen. The artwork is 386x1080, so height is the constraint and
     width follows it - a width-driven card runs to ~970px tall and the captions
     fall off the bottom. */
  max-height: min(540px, 56vh);
  width: auto;
  max-width: 100%;
  border-radius: 200px;
  box-shadow: 0 0 10px 0 rgba(0, 0, 0, .5);
  transform: scale(1);
}
@media (prefers-reduced-motion: no-preference) {
  .service img { transition: transform .3s ease; }
}
.service img:hover { transform: scale(.8); }

/* ---------- script banners ---------- */
/* The original sets these lines as artwork rather than text, centred at 25% of
   the container. Kept as images so the lettering matches the stickers and the
   Facebook artwork exactly. */
.banner { text-align: center; margin: 2rem 0; }
.banner img { display: inline-block; width: 25%; min-width: 200px; }
.banner-wide img { width: 42%; min-width: 240px; }
/* The sign-off is a flourish, not a section - keep it small and tight. */
.banner-signoff { margin: 1.25rem 0 0.5rem; }
.banner-signoff img { width: 26%; min-width: 190px; }

/* ---------- generic cards ---------- */

.grid { display: grid; gap: 24px; margin-top: 2rem; }
.grid-3 { grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); }

.card { background: var(--paper); border: 1px solid var(--line);
        border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden; }
.pad { padding: 24px; }
.card h2, .card h3 { margin-top: 0; }
.card-photo { aspect-ratio: 4 / 3; background: var(--mint-wash); overflow: hidden; }
.card-photo img { width: 100%; height: 100%; object-fit: cover; }
.photo-blank { width: 100%; height: 100%; display: grid; place-items: center; }
.photo-blank img { width: 64px; opacity: .45; }
.feature { display: grid; grid-template-columns: minmax(200px, 340px) 1fr; }
.feature .card-photo { aspect-ratio: auto; height: 100%; }
.thumb { max-width: 220px; border-radius: 12px; margin-top: .5rem; }

.list { list-style: none; margin: 2rem 0 0; padding: 0; display: grid; gap: 16px; }
.row { display: flex; align-items: center; justify-content: space-between;
       gap: 16px; flex-wrap: wrap; }
.muted { color: var(--ink-soft); }
.small { font-size: .9rem; }
.meta { color: var(--ink-soft); font-size: .92rem; margin: 0 0 .5em; }
.detail { white-space: pre-line; }
.empty { color: var(--ink-soft); font-style: italic; }
.note { margin-top: 2rem; }

.pill { display: inline-block; font-family: var(--sans); font-size: .7rem;
        font-weight: 900; text-transform: uppercase; letter-spacing: .08em;
        padding: 4px 10px; border-radius: 999px; vertical-align: middle;
        background: var(--mint-wash); color: var(--mint-dark); }
.pill-pending { background: #fdf3e0; color: #93670f; }
.pill-rehomed { background: #eeeeee; color: #555; }
.pill-draft   { background: #f2f2f2; color: var(--ink-soft); }

/* ---------- supporters ---------- */
/* The original is an Elementor image carousel: three visible, autoplay every
   3s, 300ms slide, infinite, paused on hover, arrows both sides in brand green.
   Rebuilt here rather than imported, but the numbers are the original's. */

.carousel { position: relative; padding: 0 48px; margin-top: 2rem; }
.carousel-viewport {
  overflow: hidden;
  scrollbar-width: none;           /* the arrows are the control, not a scrollbar */
}
.carousel-viewport::-webkit-scrollbar { display: none; }
.carousel-track {
  display: flex;
  align-items: center;
  list-style: none;
  margin: 0;
  padding: 0;
}
/* No scroll-behavior here on purpose: app.js passes the behaviour to scrollTo
   explicitly, so the two cannot disagree. */
.carousel-slide {
  flex: 0 0 calc(100% / 3);
  display: grid;
  place-items: center;
  padding: 10px 18px;
  /* Reserve the row's height. The logos are lazy-loaded and the carousel sits
     below the fold, so without this it renders 20px tall and the page jumps
     when they arrive. */
  min-height: 130px;
}
.carousel-slide img { max-height: 110px; width: auto; object-fit: contain; }
.carousel-slide span {
  font-family: var(--heading); font-weight: 700; font-size: .85rem;
  color: var(--mint); text-align: center;
}
.carousel-btn {
  position: absolute; top: 50%; transform: translateY(-50%);
  background: none; border: 0; cursor: pointer; padding: 6px 10px;
  font-size: 40px; line-height: 1; color: var(--mint);
}
.carousel-btn:hover { color: var(--mint-dark); }
.carousel-prev { left: 0; }
.carousel-next { right: 0; }

/* ---------- donate ---------- */

.bank { margin: 0; }
.bank dt { font-family: var(--sans); font-weight: 900; font-size: .72rem;
           text-transform: uppercase; letter-spacing: .12em;
           color: var(--mint); margin-top: 1.1rem; }
.bank dd { margin: .1rem 0 0; font-size: 1.15rem; font-weight: 700; }

.cta { background: var(--mint); color: #fff; border-radius: var(--radius);
       text-align: center; padding: 3rem 24px; }
.cta h2, .cta a { color: #fff; }
.cta .lede { color: rgba(255, 255, 255, .9); margin-inline: auto; }
.cta .btn { background: #fff; color: var(--mint-dark); }
.cta .btn:hover { background: var(--ink); color: #fff; }

/* ---------- forms + buttons ---------- */

.btn {
  display: inline-block; background: var(--mint); color: #fff;
  border: 1px solid transparent; border-radius: 999px;
  padding: 11px 24px; font-family: var(--sans); font-weight: 700; font-size: .95rem;
  text-decoration: none; cursor: pointer; text-align: center;
}
.btn:hover { background: var(--ink); color: #fff; }
.btn-sm { padding: 7px 16px; font-size: .88rem; }
.btn-ghost { background: transparent; color: var(--ink); border-color: var(--line); }
.btn-ghost:hover { background: var(--mint-wash); color: var(--mint-dark); }
.btn-quiet { background: transparent; color: var(--ink-soft); border-color: var(--line); }
.btn-quiet:hover { background: #f0f0f0; color: var(--ink); }
.btn-danger { background: transparent; color: #a33a28; border-color: #eccfc9; }
.btn-danger:hover { background: #fbeeeb; color: #82291a; }

.stack { display: grid; gap: 15px; }
.two { display: grid; gap: 15px; grid-template-columns: 1fr 1fr; }
label { display: grid; gap: 5px; font-family: var(--sans); font-size: .85rem;
        font-weight: 700; color: var(--ink-soft); }
label.check { display: flex; align-items: center; gap: 9px; font-weight: 400; }
input, select, textarea {
  font-family: var(--sans); font-size: 1rem; font-weight: 400; color: var(--ink);
  background: var(--paper); border: 1px solid var(--line);
  border-radius: 10px; padding: 10px 13px; width: 100%;
}
input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--mint); outline-offset: 1px; border-color: var(--mint);
}
input[type="checkbox"] { width: auto; }
textarea { resize: vertical; }
.inline { display: inline; }
.row-actions { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.admin-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.admin-list .row-actions { margin-left: auto; }

.alert { background: #fbeeeb; border: 1px solid #eccfc9; color: #82291a;
         padding: 12px 16px; border-radius: 12px; }
.alert-ok { border-color: var(--mint); background: var(--mint-wash); color: var(--ink); }
.code-block { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: .9rem;
              background: var(--shell); border: 1px solid var(--line);
              padding: 12px 14px; border-radius: 10px; word-break: break-all; }
.codes { list-style: none; padding: 0; margin: 1rem 0; display: grid;
         grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 8px;
         font-family: ui-monospace, Menlo, Consolas, monospace; font-size: .95rem; }
.codes li { background: var(--paper); border: 1px solid var(--line);
            border-radius: 9px; padding: 8px 12px; }
.qr { width: 190px; height: 190px; background: #fff; border: 1px solid var(--line);
      border-radius: 12px; padding: 10px; }

/* ---------- footer ---------- */

.site-foot {
  background: var(--shell); border-top: 1px solid var(--line);
  padding-block: 1.4rem; margin-top: 2rem;
  flex-shrink: 0;
}
.foot-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; text-align: left;
}
.foot-brand-block { display: grid; gap: 2px; }
.foot-brand { font-family: var(--display); font-size: 1.25rem; margin: 0; color: var(--ink); }
.foot-npo { color: var(--ink-soft); font-size: .8rem; margin: 0 0 .4rem; }
.site-foot nav { display: flex; gap: 14px; flex-wrap: wrap; }
.site-foot a { color: var(--ink-soft); text-decoration: none;
               font-family: var(--heading); font-weight: 700; font-size: .84rem; }
.site-foot a:hover { color: var(--mint-dark); }
/* Takes the space left between the brand block and the logo and centres itself
   in it, so the credit reads as the middle of the footer without either of the
   other two having to move. */
.foot-credit { flex: 1 1 auto; text-align: center; margin: 0; }

/* The house credit, shared with the other EHTech sites. Same markup, same
   script, same behaviour - only the two colours below are this site's. The
   animation is transform-free and only ever swaps text, so the resting size of
   the link never changes and the footer does not reflow while it types. */
.credit {
  display: inline-block; color: var(--ink-soft); text-decoration: none;
  font-size: .8rem; font-weight: 400;
  transition: color .18s ease;
}
.credit b { color: var(--mint-dark); font-weight: 700; transition: color .18s ease; }
.credit:hover { color: var(--ink); }
.credit:hover b { color: var(--mint); }
.credit:focus-visible { outline: 2px solid var(--mint); outline-offset: 3px; border-radius: 2px; }

/* The whole string stays in the DOM for assistive tech; the typed spans are
   aria-hidden, so the accessible name is "Built by EHTech" however much of it
   is on screen at the time. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

/* The caret exists only while the script is driving the typing. */
.credit-caret { display: none; }
.js-type .credit-caret {
  display: inline-block; width: 1px; height: 1em; margin-left: 2px;
  background: var(--mint-dark); vertical-align: -2px;
  animation: caret-blink 1s steps(2, start) infinite;
}
.js-type .credit.is-idle .credit-caret { animation: none; opacity: 1; }
@keyframes caret-blink { 0% { opacity: 1 } 50% { opacity: 0 } 100% { opacity: 1 } }

/* Nothing types for anyone who asked for less motion: the credit is simply
   there, whole, with no caret. */
@media (prefers-reduced-motion: reduce) {
  .js-type .credit-caret { display: none; }
}

/* The logo fills the footer's right-hand edge: it sets the band's height rather
   than sitting inside it, which is what makes the footer read as one piece. */
.foot-logo { height: 96px; width: auto; flex: 0 0 auto; }

@media (max-width: 1024px) {
  .carousel-slide { flex-basis: 50%; }
}

/* 767px is the original's mobile breakpoint. Three service cards hold all the
   way down to it and then stack straight to one - there is no two-up stage. */
@media (max-width: 767px) {
  .services { grid-template-columns: 1fr; gap: 24px; }
  .service img { max-height: none; max-width: 300px; }
  .carousel-slide { flex-basis: 100%; }
  .carousel { padding: 0 40px; }
  .banner img, .banner-wide img { width: 78%; }
}

@media (max-width: 760px) {
  .two, .feature { grid-template-columns: 1fr; }
  .admin-list .row-actions { margin-left: 0; }
  .service { border-radius: 120px 120px var(--radius) var(--radius); }

  /* Stacked and centred on a phone. Side by side, the wordmark loses the width
     fight with the social buttons and ends up smaller than them. */
  .head-inner { grid-template-columns: 1fr; justify-items: center; gap: 12px; }
  .brand-mark, .brand, .head-side { justify-self: center; }
  .brand-mark { display: none; }
  .brand img { width: min(280px, 74vw); }
  .site-nav { grid-column: auto; }
  .head-side { flex-direction: column; }
  /* Smaller clouds and less padding on a phone - at desktop size the header
     eats better than half the screen before any content appears. */
  .site-head { padding: 20px 0 58px;
               background-size: calc(100% + 1.3px) 50%, 100% 100%; }
  .foot-inner { flex-direction: column; text-align: center; }
  .foot-brand-block { justify-items: center; }
  .site-foot nav { justify-content: center; }
  .foot-logo { height: 76px; order: -1; }
}

@media (prefers-reduced-motion: no-preference) {
  a, .btn { transition: background-color .15s ease, color .15s ease; }
}
