# Footer & Call To Action

## Footer & Call To Action

**Files:** `src/config/config.toml`, `src/i18n/en.json`, `src/config/menu.en.json`, `src/config/social.json`, `src/content/sections/english/cta-section.md` · **Skill level:** Beginner

In the Tina edition, these are under **Site settings**, **Menus**, **Social links**, and **Interface labels** at `/admin/`. In the Sanity edition, they are in the Studio under **Site settings**, **Menus**, and **Interface labels**, and the section under **Sections > CTA section**.

### Choose A Footer Layout
Ecozen has four footer layouts. All of them read the same menus, services, social links, contact details, and text, so you can switch at any time.

```toml
# src/config/config.toml
[settings.footer]
  layout = "wordmark"   # wordmark | newsletter | cta | contact
```

| Layout       | What it shows                                                                                       | Demo page      |
| ------------ | --------------------------------------------------------------------------------------------------- | -------------- |
| `wordmark`   | Dark footer that opens with the logo and a large closing line. Beside it: rows for your phone, your email, and a quote link, each with an arrow. Below: **Services**, **Pages**, **Visit us** (address and opening hours), and **Follow** (social links as text) columns, the copyright and legal links, an outlined wordmark, and a line drawing of solar trackers along the bottom edge | `/`            |
| `newsletter` | A citrus call-to-action band over the top edge, with a closing line, a button, your phone number, and an arch-shaped photo. Below, on a dark background with faint power-pylon drawings: logo, address, and social icons; your phone and email; **Services**; and a **Subscribe** column with the email sign-up form. Then the copyright and legal links | `/home-two/`   |
| `cta`        | A photo band over the top edge, with a caption pill, a closing line, a button, and a card of current projects. Below, on a dark background: logo, description, and social icons; **Pages**; **Legal**; and **Contact** (address, email, phone, and opening hours). Then the copyright and a row of line-drawn wind turbines with turning blades | `/home-three/` |
| `contact`    | Light footer that opens with a mint dotted panel: a reply-time line, your phone number in large type, your email, address, and opening hours, and a card where visitors check if you work in their postcode. Below it: logo, description, and trust pills; **Pages**, **Services**, and **Legal** columns; the copyright and social icons | `/home-four/`  |

The wordmark is `[site] title`. The dark layouts, `wordmark`, `newsletter`, and `cta`, use the light logo (`logoAlternate`); `contact` uses the normal one (`logo`). The solar trackers tilt slowly to follow the sun and the turbine blades turn. The outlined wordmark rises into place as it scrolls into view, in browsers that support scroll-linked motion. All of these stand still for visitors who turn on reduced motion.

**One page, another layout.** Add `footerLayout` to the page's frontmatter. It wins over `[settings.footer] layout`:

```yaml
---
footerLayout: "cta"   # wordmark | newsletter | cta | contact
title: "Wind, solar, and storage developer"
---
```

Each demo homepage sets its own: `/` uses `wordmark`, `/home-two/` uses `newsletter`, `/home-three/` uses `cta`, and `/home-four/` uses `contact`. Every other page uses `[settings.footer] layout`, which ships as `wordmark`. If you keep one homepage, remove its `footerLayout` line or set it to the layout you use everywhere. It works on any page whose frontmatter reaches `<Base>`, which every shipped route does except the 404 pages. `npm run astro-check` reports a misspelled value in files that have a schema.

### Footer Text
Edit `footer` in `src/i18n/en.json` (and the file for each other language):

```json
"footer": {
  "description": "Solar panels, battery storage, and EV charging for homes and businesses.",
  "copyright": "© {{ year }} Ecozen. All rights reserved.",
  "company": "Company",
  "social": "Social",
  "contact": "Contact",
  "phone": "Phone",
  "email": "Email",
  "address": "Address",
  "hours": "Opening hours",
  "hoursText": "",
  "newsletter": { ... },
  "cta": { ... },
  "contactPanel": { ... },
  "band": { ... },
  "statement": { ... },
  "subscribe": "Subscribe"
}
```

- `{{ year }}` becomes the year of the build, so the year updates each time you rebuild the site.
- The copyright accepts Markdown links. Replace the shipped name with your own business.
- `description` is the short text under the logo in the `cta` and `contact` layouts.
- The **Pages**, **Services**, and **Legal** headings are `common.pages`, `common.services`, and `common.legal`.
- `phone` and `email` label the phone and email rows of the `wordmark` and `newsletter` layouts. `contact` is the heading of the **Contact** column in the `cta` layout. `address`, `email`, `phone`, and `hours` name its rows for screen readers.
- `hoursText` replaces the opening hours from `[settings.contactInfo] hours` for one language, for example `"Lun–Ven, 8h00–18h00"` in `fr.json`. Empty uses `hours`.
- `subscribe` is the heading of the sign-up column in the `newsletter` layout.
- `statement`, `band`, `newsletter`, `cta`, and `contactPanel` hold the text of each layout. They are described with each layout below.
- `company` and `social` are not shown by the current footer layouts. You can leave them as they are.
- For a one-language site you can set the text in `config.toml` instead: `footerDescription` under `[settings]`, and `text` under `[settings.copyright]`. `[settings.copyright] enable = false` hides the line.

### Footer Links
| Part              | Where it comes from                                                   | Layouts                              |
| ----------------- | --------------------------------------------------------------------- | ------------------------------------ |
| **Pages** links   | `footerSecondary` in `src/config/menu.en.json`                        | `wordmark`, `cta`, `contact`         |
| **Services** links | Your first six services by `weight`                                  | `wordmark`, `newsletter`, `contact`  |
| **Legal** links   | `footerPrivacy` in `src/config/menu.en.json`                          | All four                             |
| Social links      | The first four enabled links in `src/config/social.json`              | All four                             |
| Phone, email, address, hours | `[settings.contactInfo]` in `src/config/config.toml`       | All four (each shows a different mix) |

See [Menus](/ecozen/customization/menus/) for the link lists. `"enable": false` hides a link. An empty value in `[settings.contactInfo]` hides its row.

### The AI Row And The Theme Credit
All four layouts end with the same two extras, placed by `src/layouts/components/global/footer/FooterBottom.astro`.

**The AI row** (`FooterAi.astro`) has **Ask AI** links that open an assistant with a question about the current page, and links to the page's Markdown copy, `llms.txt`, and `llms-full.txt`. Change it in `[settings.pageActions]`: `footer = false` removes the row, and `providers` sets the assistants. Its words are `ai.footerAsk`, `ai.footerRead`, and `ai.footerMarkdown` in the i18n files. See [AI Links & llms](../../features/ai-links-llms/).

**The theme credit** (`FooterCredit.astro`) is editable in `config.toml`, and it is the same in every language. The part of `text` in `[brackets]` becomes the link:

```toml
[settings.themeCredit]
  enable = true
  text   = "..."
  url    = "..."
```

### Wordmark Layout
The large closing line and the quote row come from `footer.statement` in the i18n files:

```json
"statement": {
  "title": "Your roof can power more of your home than you think.",
  "text": "Free roof survey, fixed price",
  "button": "Get a free quote",
  "visit": "Visit us",
  "follow": "Follow",
  "top": "Back to top"
}
```

| Key              | What it does                                                                     |
| ---------------- | -------------------------------------------------------------------------------- |
| `title`          | The large closing line under the logo                                            |
| `text`, `button` | The small label and the link text of the quote row. It links to `[settings.footer.band] url` |
| `visit`          | The heading of the column with your address and opening hours                    |
| `follow`         | The heading of the column with your social links                                 |
| `top`            | Not shown by the current layout. You can leave it as it is                       |

The phone and email rows show `phone` and `email` from `[settings.contactInfo]`. The **Follow** column lists your social links by their `label`, as text with an arrow.

### Footer Band
The `newsletter` and `cta` layouts open with a rounded call-to-action band. Its top half sits over the end of the page and its bottom half over the footer. Set it in `config.toml`:

```toml
[settings.footer.band]
  enable   = true
  url      = "/contact/"                       # the button link; also the quote row of the "wordmark" layout
  image    = "/images/photos/your-photo.jpg"   # the arch photo of the "newsletter" layout; empty hides it
  imageAlt = "Describe the photo"
```

- `enable = false` removes the band from both layouts.
- The band hides on its own on pages that have a call-to-action section, so the page doesn't close with two calls to action in a row. See [The Call To Action Above The Footer](#the-call-to-action-above-the-footer) below.
- In the `newsletter` layout the band text comes from `footer.band` in the i18n files. In the `cta` layout it is the photo band described under [CTA Layout](#cta-layout) below.

```json
"band": {
  "title": "Have questions about going solar? We're here to help.",
  "button": "Get a free quote",
  "help": "Need any help?"
}
```

`title` is the closing line and `button` the button text. `help` is the small line above your phone number, which comes from `[settings.contactInfo] phone`. Without a phone number, the phone link hides. The arch photo shows on large screens only.

### Newsletter Layout
Below the [footer band](#footer-band), the left column shows the light logo, your address, and social icons. Next come your phone and email from `[settings.contactInfo]` as links, then your **Services**, then a **Subscribe** column with the sign-up form. The bottom row has the copyright and the legal links (`footerPrivacy`).

The sign-up form is set in `config.toml`:

```toml
[settings.newsletter]
  enable   = true
  action   = "https://formsubmit.co/your@email.com"   # placeholder: set your own
  provider = "formsubmit.co"                          # formsubmit.co | formspree | netlify | ""
```

| `provider`        | `action`                                  | How it sends                                              |
| ----------------- | ----------------------------------------- | --------------------------------------------------------- |
| `"formsubmit.co"` | `https://formsubmit.co/you@your-domain.com` | In the background, with a status message under the field |
| `"formspree"`     | `https://formspree.io/f/your-form-id`     | In the background, with a status message                 |
| `"netlify"`       | `"/"`                                     | In the background, as a Netlify form named `newsletter`   |
| `""`              | Any other sign-up URL, for example a mailing-list tool's form URL | A normal form post to that address |

The form sends one field, `email`. A mailing-list tool that expects a different field name needs a small change in `src/layouts/components/widgets/NewsletterForm.astro`; test a sign-up after you connect it. `enable = false`, or an empty `action`, removes the whole **Subscribe** column. Its text is in `footer.newsletter` in the i18n files:

```json
"newsletter": {
  "label": "Energy tips and project news, once a month.",
  "emailLabel": "Email address",
  "placeholder": "Enter your email",
  "button": "Subscribe",
  "submitting": "Sending…",
  "success": "Thanks. Please check your inbox to confirm.",
  "error": "We couldn't sign you up. Please try again or email us.",
  "subject": "New newsletter sign-up",
  "note": "One email a month. Unsubscribe anytime."
}
```

`label` is the line above the field and `note` the small line under it. The submit button shows an arrow icon; `button` is its name for screen readers. `emailLabel` names the field for screen readers. `submitting`, `success`, and `error` are the status messages, and `subject` is the subject line of the email you receive from `formsubmit.co` or `formspree`.

<Aside type="caution">
  The shipped `action` is a placeholder address. Set your own, or the
  sign-ups go nowhere. While `action` is still a placeholder, or doesn't
  match the `provider`, `npm run dev` and `npm run build` print a `[forms]`
  warning in the terminal. On the dev server only, the form also shows a
  short "Dev only · form not connected" note after you submit it. Your built site never shows that note.
</Aside>

### CTA Layout
The `cta` layout opens with a photo band in the [footer band](#footer-band) position. Its photo, closing line, and button are set in `config.toml`:

```toml
[settings.footer.cta]
  enable   = true
  title    = ""          # empty uses footer.cta.title from the i18n files
  label    = ""          # empty uses footer.cta.button
  url      = "/contact/"
  image    = "/images/photos/your-photo.jpg"   # the photo behind the band; empty hides it
  imageAlt = "Describe the photo"
```

Leave `title` and `label` empty for a site in several languages and write the text in `footer.cta.title` and `footer.cta.button` in each file in `src/i18n/`. `enable = false`, or `[settings.footer.band] enable = false`, hides the whole photo band. Put the photo in `src/assets/images/` like your other images, and describe it in `imageAlt`. The photo settles from a slight zoom as the footer scrolls into view.

The caption pill and the project card come from `footer.cta` in the i18n files:

```json
"cta": {
  "title": "Clean power, built to run for decades.",
  "button": "Work with us",
  "caption": "Ridge wind farm · 24 MW · operating",
  "projectsTitle": "Current projects",
  "projects": [
    { "name": "Hillside solar park", "size": "32 MW", "status": "Operating", "live": true },
    { "name": "Coastal wind farm", "size": "18 MW", "status": "Building" },
    { "name": "Valley battery site", "size": "40 MWh", "status": "Planning" }
  ]
}
```

| Key             | What it does                                                                         |
| --------------- | ------------------------------------------------------------------------------------ |
| `caption`       | The small pill above the closing line. Empty hides it                                |
| `projectsTitle` | The heading of the project card                                                      |
| `projects`      | One row per project: `name`, `size`, and a `status` pill. `"live": true` fills the pill with the brand color; leave it out for an outlined pill. An empty list (`[]`) hides the whole card |

The sample projects are placeholders. List your own, or set `"projects": []`. Change them in every language file.

Below the band, the **Contact** column shows `address`, `email`, `phone`, and `hours` from `[settings.contactInfo]`.

### Contact Layout
The mint panel shows `phone`, `email`, `address`, and `hours` from `[settings.contactInfo]` in `config.toml`. The phone number is shown large and, like the email, becomes a link. The email, address, and hours sit in small pills. To show the opening hours differently in one language, write them in `footer.hoursText` in that language's i18n file; empty uses `hours`. An empty value hides its row.

**Area check.** The card on the right asks for a postcode and answers on the spot whether you work there. Set the postcodes you cover and the quote page in `config.toml`:

```toml
[settings.footer.contact]
  url       = "/contact/"                  # the quote page the answer links to
  postcodes = ["SP1", "SP2", "RV4", "GF7"]  # placeholder: the postcode prefixes you cover
```

- Each value is the **start** of a postcode. `"SP1"` matches `SP1 4AB` and `sp14ab`: case and spaces don't matter. A prefix also matches longer ones, so `"SP1"` matches `SP12 3CD` too.
- After the answer, a link sends the visitor to `url` with the postcode they typed.
- With an empty list (`postcodes = []`), or when JavaScript is off, the form doesn't answer. It opens the quote page instead.
- The shipped postcodes are placeholders. Replace them with your own, or empty the list.

The panel's text is in `footer.contactPanel` in the i18n files:

```json
"contactPanel": {
  "status": "Replies within 2 working hours",
  "areaTitle": "Do we install in your area?",
  "areaText": "Enter your postcode to check before you ask for a quote.",
  "areaLabel": "Postcode",
  "areaPlaceholder": "Postcode",
  "areaButton": "Check",
  "areaYes": "Good news: we install in {postcode}.",
  "areaNo": "{postcode} is outside our usual area, but we may still cover it.",
  "areaLink": "Ask for a quote",
  "badges": ["Certified installer", "10-year workmanship warranty", "Fully insured"]
}
```

| Key                 | What it does                                                                     |
| ------------------- | -------------------------------------------------------------------------------- |
| `status`            | The short line with a dot above the phone number, for example your reply time    |
| `areaTitle`, `areaText` | The heading and the line of text of the area-check card                      |
| `areaLabel`         | The name of the postcode field for screen readers                                |
| `areaPlaceholder`, `areaButton` | The hint inside the field and the button text                        |
| `areaYes`, `areaNo` | The answer when the postcode is or isn't on your list. `{postcode}` is replaced with what the visitor typed |
| `areaLink`          | The link after the answer                                                        |
| `badges`            | The trust pills under the footer description. An empty list (`[]`) hides them. Only list what is true for your business |

### Social Links
`src/config/social.json` lists your profiles. Change `url`, or set `enable: false` to hide one:

```json
{
  "main": [
    {
      "enable": true,
      "label": "Linkedin",
      "url": "https://www.linkedin.com/company/your-company"
    }
  ]
}
```

`label` picks the icon. These labels have one: `Facebook`, `X`, `Twitter`, `Linkedin`, `Instagram`, `Github`, `Youtube`, `Pinterest`, and `Dribbble`. The demo uses `X`, which shows the X logo. The footer shows the first four enabled links, so put the ones you care about first: as icons in the `newsletter`, `cta`, and `contact` layouts, and as text links named by `label` in the **Follow** column of the `wordmark` layout. The mobile menu panel uses the same file.

### The Call To Action Above The Footer
Most pages end with a call-to-action band above the footer: a photo, a badge, a title, a short text, and a button. Its default content is `src/content/sections/english/cta-section.md`:

```yaml
---
enable: true
options:
  layout: "band"   # band | split
badge: "Free roof survey"
title: "Find out what your roof can save"
description: "Book a free roof survey. You get a panel layout, a fixed price, and yearly savings within two working days."
image: "/images/photos/band-cta-unsplash-Ilpf2eUPpUE.jpg"
imageAlt: "Aerial view of a solar array in green fields"
buttons:
  - enable: true
    label: "Get a free quote"
    url: "/contact/"
    variant: "fill"
    class: "btn-accent"
showPhone: false   # true adds the phone number from [settings.contactInfo]
---
```

Each route places the band itself, so a page can change it with a `ctaSection` block in its own file. The contact, calculator, careers, and projects pages already do. For example, in `src/content/contact/english/-index.md`:

```yaml
ctaSection:
  enable: true
  badge: "Not ready to talk yet?"
  title: "Estimate your savings first"
  buttons:
    - enable: true
      label: "Open the calculator"
      url: "/calculator/"
      variant: "fill"
      class: "btn-accent"
```

It has two layouts, set with `options.layout`:

| Layout  | What it looks like                                                                    |
| ------- | ------------------------------------------------------------------------------------- |
| `band`  | The default. A full-width photo with the badge, title, text, and buttons on a glass card in the middle |
| `split` | A light mint panel with rounded corners: the badge, title, text, and buttons on the left, and the photo in a rounded frame on the right, with no overlay. On small screens the photo moves below the text |

In both layouts the photo moves a little slower than the page as you scroll.

The pricing page uses `split`, with two buttons. In `src/content/pricing/english/-index.md`:

```yaml
ctaSection:
  options:
    layout: "split"   # band | split
  badge: "Your price"
  title: "Get a fixed price for your roof"
  image: "/images/photos/your-photo.jpg"
  imageAlt: "Describe the photo"
  buttons:
    - enable: true
      label: "Get a free quote"
      url: "/contact/"
      variant: "fill"
    - enable: true
      label: "Estimate savings"
      url: "/calculator/"
      variant: "outline"
```

The page's buttons replace the default ones: a dark `fill` button and an `outline` one read well on the light panel. `showPhone: true` works in both layouts.

To hide it on one page, write `enable: false` in that page's `ctaSection` block. The `ctaSection` block in `src/content/projects/english/-index.md` also applies to every project page. Blog pages always use the default band, and the 404 and job pages have none.

The homepages `/` and `/home-two/` turn the band off with `enable: false`, and `/home-three/` has none, so their footers close the page instead. On a page that keeps this band, the [footer band](#footer-band) of the `newsletter` and `cta` layouts hides, so the page doesn't end with two calls to action.

### Do It With AI
```text
Set the footer to the [wordmark | newsletter | cta | contact] layout in [settings.footer] of
src/config/config.toml, and remove footerLayout from the homepage files I keep. Change
footer.description, footer.copyright, footer.statement, and footer.band in every file in src/i18n/
for my business "[NAME]" (keep {{ year }}). Set [settings.footer.band] url to my quote page. [For the newsletter layout: set [settings.newsletter] action to [URL] and
provider to [PROVIDER].] [For the contact layout: set [settings.footer.contact] postcodes to
[POSTCODE PREFIXES] and rewrite footer.contactPanel (badges: [MY REAL CERTIFICATIONS]).] [For the
cta layout: set [settings.footer.cta] image and imageAlt to [PHOTO], and footer.cta.caption and
footer.cta.projects to [MY PROJECTS], in every i18n file.] Update src/config/social.json with my profiles: [LINKS], and disable the
others. Then rewrite cta-section.md in every language folder of src/content/sections/ for my business,
keeping every key and option.
```