backend:
  name: github
  repo: ntcreation/fellowship-film
  branch: main
  auth_endpoint: api/cms/auth
  commit_messages:
    create: "content: create {{collection}} “{{slug}}”"
    update: "content: update {{collection}} “{{slug}}”"
    delete: "content: delete {{collection}} “{{slug}}”"
    uploadMedia: "content: upload “{{path}}”"
    deleteMedia: "content: delete “{{path}}”"

site_url: https://ffnew.fellowshipfilm.com

media_folder: public/media
public_folder: /media

media_libraries:
  default:
    config:
      max_file_size: 26214400
      slugify_filename: true
      transformations:
        raster_image:
          format: webp
          quality: 82
          width: 2400
          height: 2400

output:
  omit_empty_optional_fields: true

slug:
  encoding: ascii
  clean_accents: true

collections:
  - name: films
    label: Films
    label_singular: Film
    folder: content/films
    preview_path: "films/{{slug}}/"
    create: true
    extension: md
    format: frontmatter
    sortable_fields: [order, title]
    summary: "{{title}} · {{status}}"
    fields:
      - { name: title, label: Title, widget: string }
      - { name: logline, label: Logline (one sentence), widget: text, hint: "Who, what they want, what stands in the way. No dashes." }
      - name: status
        label: Status
        widget: select
        options:
          - { label: Released (watch now), value: released }
          - { label: Post-production (coming soon), value: post-production }
          - { label: In development, value: in-development }
      - { name: year, label: Year, widget: number, required: false, value_type: int }
      - { name: runtime, label: Runtime (minutes), widget: number, required: false, value_type: int }
      - { name: genre, label: Genre, widget: string, required: false }
      - { name: rating, label: Age rating (e.g. PG), widget: string, required: false }
      - { name: format, label: Format, widget: select, options: [feature, short], default: feature }
      - { name: poster, label: "Poster (2:3)", widget: image }
      - { name: backdrop, label: Backdrop (wide still), widget: image }
      - { name: card, label: "Card (16:9, title on it)", widget: image, required: false, hint: "Shown in film rows. 960 × 540. If empty, the backdrop is used. A developer can make one with scripts/make-card.mjs" }
      - { name: backdropHasTitle, label: Backdrop has the title written on it, widget: boolean, default: false, hint: "Tick if the backdrop shows the film's name. The film page then uses the first still instead." }
      - { name: backdropFocus, label: Backdrop focus point, widget: string, required: false, hint: "Where the subject is, across then down, e.g. 30% 30%" }
      - { name: titleImage, label: Title art (transparent PNG), widget: image, required: false }
      - { name: stills, label: Stills, widget: image, multiple: true, required: false }
      - { name: trailerYoutubeId, label: Trailer YouTube ID, widget: string, required: false, hint: "The part after watch?v= in the YouTube link" }
      - { name: trailerFile, label: Trailer video file (MP4 under 25 MB), widget: file, required: false, hint: "Used instead of YouTube if set" }
      - { name: trailerImage, label: Trailer cover image (a still), widget: image, required: false }
      - name: watch
        label: Where to watch
        widget: list
        required: false
        hint: "Most important first. The film page shows the top three for each visitor's region. To offer the film on this site, add an entry whose link starts with / and it is always shown first."
        fields:
          - { name: label, label: Service, widget: string }
          - { name: url, label: Link, widget: string }
          - { name: region, label: Region, widget: select, options: [UK, US, Ireland, Canada, Australia, Worldwide], default: Worldwide }
          - { name: note, label: "How (e.g. rent or buy)", widget: string, required: false }
      - name: credits
        label: Credits
        widget: list
        required: false
        fields:
          - { name: role, label: Role, widget: string }
          - { name: name, label: Name, widget: string }
      - name: specs
        label: Facts for distributors
        widget: list
        required: false
        hint: "e.g. Format, Aspect ratio, Sound, Language"
        fields:
          - { name: label, label: Label, widget: string }
          - { name: value, label: Value, widget: string }
      - { name: pressKit, label: Press kit (PDF), widget: file, required: false }
      - { name: featureVimeoId, label: Film on Vimeo (video ID), widget: string, required: false, hint: "The number in the Vimeo link. Needed to sell or stream the film here." }
      - { name: thanksText, label: Line under Thanks for watching (optional), widget: text, required: false, hint: "Shows when the film ends. Leave empty for none." }
      - { name: creditsAt, label: End credits start at, widget: string, required: false, hint: "A timecode like 1:18:13. From here the film counts as watched. Leave empty to use the last 5%." }
      - { name: featureVimeoHash, label: Vimeo privacy hash, widget: string, required: false, hint: "For unlisted videos: the part after the ID in the private link, e.g. abc123 in vimeo.com/123/abc123" }
      - name: sale
        label: Selling on this site
        widget: object
        collapsed: true
        required: false
        hint: "Prices in pounds, e.g. 9.99. Needs the Vimeo ID above and the shop switched on in Features."
        fields:
          - { name: filmOn, label: Sell the film, widget: boolean, default: true }
          - { name: filmPrice, label: Film price, widget: number, value_type: float, required: false }
          - { name: bundleOn, label: Sell the bundle (film and extras), widget: boolean, default: false }
          - { name: bundlePrice, label: Bundle price (lowest), widget: number, value_type: float, required: false, hint: "Buyers can choose to pay more if that is switched on in Features" }
          - { name: currency, label: Currency, widget: string, default: GBP, hint: "Three letters, e.g. GBP" }
      - name: extras
        label: Extras (come with the bundle)
        widget: list
        required: false
        hint: "Only extras with a Vimeo ID or a file show to buyers."
        fields:
          - { name: title, label: Title, widget: string }
          - { name: kind, label: Kind, widget: select, options: [{ label: Video, value: video }, { label: Download, value: download }], default: video }
          - { name: vimeoId, label: Vimeo ID (videos), widget: string, required: false }
          - { name: vimeoHash, label: Vimeo privacy hash (videos), widget: string, required: false }
          - { name: file, label: File name in storage (downloads), widget: string, required: false, hint: "Ask Nathan to upload it to private storage, e.g. jessie-and-the-elf-boy/screenplay.pdf" }
          - { name: text, label: Short description, widget: string, required: false }
      - { name: availableIn, label: Licensed in (country codes), widget: list, required: false, hint: "e.g. GB, IE. Use worldwide, or leave empty, for everywhere." }
      - { name: blockedIn, label: Not licensed in (country codes), widget: list, required: false, hint: "Exceptions, e.g. US" }
      - { name: order, label: Order on site, widget: number, value_type: int, default: 100 }
      - { name: featured, label: Homepage hero, widget: boolean, default: false }
      - { name: draft, label: Draft (hidden from site), widget: boolean, default: false }
      - &seo
        name: seo
        label: SEO
        widget: object
        collapsed: true
        required: false
        fields:
          - { name: title, label: Title, widget: string, required: false }
          - { name: description, label: Description, widget: text, required: false }
          - { name: image, label: Share image, widget: image, required: false }
      - { name: body, label: Synopsis, widget: markdown, required: false }

  - name: pages
    label: Pages
    label_singular: Page
    folder: content/pages
    preview_path: "{{slug}}/"
    create: false
    extension: md
    format: frontmatter
    fields:
      - { name: title, label: Title, widget: string }
      - { name: intro, label: Heading, widget: string, required: false }
      - { name: lede, label: One-line intro, widget: string, required: false }
      - { name: backdrop, label: Header image (wide still), widget: image, required: false }
      - { name: image, label: Portrait, widget: image, required: false }
      - *seo
      - { name: body, label: Text, widget: markdown }

  - name: services
    label: Services
    label_singular: Service
    folder: content/services
    preview_path: "services/{{slug}}/"
    create: true
    extension: md
    format: frontmatter
    sortable_fields: [order, title]
    fields:
      - { name: title, label: Title, widget: string }
      - { name: lede, label: One-line intro, widget: string }
      - { name: backdrop, label: Header image (wide still), widget: image, required: false }
      - { name: order, label: Order on site, widget: number, value_type: int, default: 100 }
      - name: packages
        label: Packages
        widget: list
        fields:
          - { name: name, label: Name, widget: string }
          - { name: price, label: Price (£), widget: number, value_type: int }
          - { name: summary, label: Summary, widget: text }
          - { name: text, label: More detail, widget: text, required: false }
      - { name: draft, label: Draft (hidden from site), widget: boolean, default: false }
      - *seo

  - name: campaigns
    label: Campaigns
    label_singular: Campaign
    folder: content/campaigns
    preview_path: "campaigns/{{slug}}/"
    create: true
    extension: md
    format: frontmatter
    fields:
      - { name: title, label: Title, widget: string }
      - { name: film, label: Film, widget: relation, collection: films, value_field: "{{slug}}", search_fields: [title], display_fields: [title], required: false }
      - { name: goal, label: Goal amount, widget: number, value_type: int }
      - { name: currency, label: Currency, widget: select, options: [GBP, EUR, USD], default: GBP }
      - { name: start, label: Start date, widget: datetime }
      - { name: end, label: End date, widget: datetime }
      - name: chargingModel
        label: Charging
        widget: select
        default: charge-now
        options:
          - { label: Charge at pledge (refund if goal missed), value: charge-now }
          - { label: Charge only if goal is met, value: charge-on-success }
      - { name: tiers, label: Tiers, widget: relation, collection: tiers, value_field: "{{slug}}", search_fields: [name], display_fields: [name], multiple: true, required: false }
      - name: faq
        label: FAQ
        widget: list
        required: false
        fields:
          - { name: question, label: Question, widget: string }
          - { name: answer, label: Answer, widget: markdown }
      - name: updates
        label: Updates
        widget: list
        required: false
        fields:
          - { name: date, label: Date, widget: datetime }
          - { name: title, label: Title, widget: string }
          - { name: body, label: Body, widget: markdown }
      - { name: draft, label: Draft (hidden from site), widget: boolean, default: false }
      - *seo
      - { name: body, label: Story, widget: markdown }

  - name: tiers
    label: Tiers
    label_singular: Tier
    folder: content/tiers
    create: true
    identifier_field: name
    extension: json
    format: json
    fields:
      - { name: name, label: Name, widget: string }
      - { name: description, label: Description, widget: text, required: false }
      - { name: price, label: Price (in pence/cents), widget: number, value_type: int }
      - { name: currency, label: Currency, widget: select, options: [GBP, EUR, USD], default: GBP }
      - name: interval
        label: Billing
        widget: select
        options:
          - { label: Monthly, value: month }
          - { label: Yearly, value: year }
          - { label: One-off, value: once }
      - { name: perks, label: Perks, widget: list, required: false }
      - { name: limit, label: Quantity limit, widget: number, value_type: int, required: false }
      - { name: grantsAccess, label: Grants film access, widget: boolean, default: false }
      - name: priceIds
        label: Payment price IDs
        widget: object
        collapsed: true
        required: false
        hint: Ask a developer before changing.
        fields:
          - { name: stripe, label: Stripe, widget: string, required: false }
      - { name: active, label: Active, widget: boolean, default: true }

  - name: people
    label: People
    label_singular: Person
    folder: content/people
    preview_path: "people/{{slug}}/"
    create: true
    identifier_field: name
    extension: md
    format: frontmatter
    fields:
      - { name: name, label: Name, widget: string }
      - { name: role, label: Role, widget: string, required: false }
      - { name: photo, label: Photo, widget: image, required: false }
      - { name: order, label: Sort order, widget: number, value_type: int, default: 100 }
      - { name: profile, label: Profile page on, widget: boolean, default: false, hint: "Only turn this on once the person has agreed to a page, and we have the right to use their photo." }
      - { name: slug, label: Page address, widget: string, required: false, hint: "Lower case and dashes, e.g. ruth-ferguson. If empty, the file name is used. Changing it changes the link." }
      - { name: creditNames, label: Other names in credits, widget: list, required: false, hint: "Any other spelling of their name used in film credits, one per line, so credits link to their page." }
      - name: links
        label: Links
        widget: list
        required: false
        hint: "e.g. IMDb, their website"
        fields:
          - { name: label, label: Label, widget: string }
          - { name: url, label: URL, widget: string }
      - { name: body, label: Bio, widget: markdown, required: false }

  - name: updates
    label: Film updates
    label_singular: Update
    folder: content/updates
    create: true
    extension: json
    format: json
    identifier_field: title
    sortable_fields: [date, title]
    summary: "{{date}} · {{title}}"
    fields:
      - { name: film, label: Film, widget: relation, collection: films, value_field: "{{slug}}", search_fields: [title], display_fields: [title] }
      - { name: date, label: Date, widget: datetime, time_format: false, date_format: "YYYY-MM-DD", format: "YYYY-MM-DD" }
      - { name: title, label: Title, widget: string }
      - name: kind
        label: Kind
        widget: select
        default: update
        options:
          - { label: Update, value: update }
          - { label: Behind the scenes, value: behind-the-scenes }
      - { name: people, label: People in this update, widget: relation, collection: people, value_field: "{{slug}}", search_fields: [name], display_fields: [name], multiple: true, required: false }
      - name: sections
        label: Sections
        widget: list
        hint: "Each section can be for everyone, followers of the film, or patrons and people who have the film. Locked sections show their first lines, then an invitation."
        fields:
          - name: audience
            label: Who can read it
            widget: select
            default: public
            options:
              - { label: Everyone, value: public }
              - { label: Followers of the film, value: followers }
              - { label: Patrons and people who have the film, value: patrons }
          - { name: text, label: Text, widget: markdown }
      - name: schedule
        label: When it goes out
        widget: list
        required: false
        hint: "Each line sends the update to one group at a set time, or puts it on the website. Everyone gets it once, at the first time any of their groups is due, with the parts they can read. With no website line, it shows on the site from its date."
        summary: "{{to}} · {{at}}"
        fields:
          - name: to
            label: To
            widget: select
            options:
              - { label: Patrons and people who have the film, value: patrons }
              - { label: Followers of the film, value: followers }
              - { label: Everyone on the mailing list, value: subscribers }
              - { label: The website, value: web }
          - { name: at, label: At, widget: datetime, format: "YYYY-MM-DDTHH:mm:ssZ" }
      - { name: draft, label: Draft (nothing goes out, hidden from site), widget: boolean, default: false }

  - name: events
    label: Events
    label_singular: Event
    folder: content/events
    preview_path: "events/{{slug}}/"
    create: true
    extension: md
    format: frontmatter
    sortable_fields: [start, title]
    summary: "{{start}} · {{title}}"
    fields:
      - { name: title, label: Title, widget: string }
      - { name: start, label: Starts (UK time), widget: datetime, format: "YYYY-MM-DDTHH:mm", picker_utc: false }
      - { name: end, label: Ends (UK time), widget: datetime, format: "YYYY-MM-DDTHH:mm", picker_utc: false, required: false }
      - { name: place, label: Place, widget: string }
      - { name: address, label: Address, widget: string, required: false }
      - { name: film, label: Film, widget: relation, collection: films, value_field: "{{slug}}", search_fields: [title], display_fields: [title], required: false }
      - { name: booking, label: Booking link (e.g. Eventbrite), widget: string, required: false }
      - { name: image, label: Image (16:9), widget: image, required: false, hint: "If empty, the film's card is used." }
      - { name: draft, label: Draft (hidden from site), widget: boolean, default: false }
      - { name: body, label: Text, widget: markdown, required: false }

  - name: newsletters
    label: Newsletters
    label_singular: Newsletter
    folder: content/newsletters
    create: true
    extension: json
    format: json
    identifier_field: subject
    summary: "{{subject}} · {{audience}}"
    description: Written here, sent by Nathan with the send script. Saving does not send anything.
    fields:
      - { name: subject, label: Subject, widget: string }
      - name: audience
        label: Send to
        widget: select
        default: everyone
        options:
          - { label: Everyone on the mailing list, value: everyone }
          - { label: Followers of one film, value: film }
      - { name: film, label: Film (for followers), widget: relation, collection: films, value_field: "{{slug}}", search_fields: [title], display_fields: [title], required: false }
      - { name: body, label: Text, widget: markdown }
      - { name: sent, label: Sent on, widget: datetime, required: false, hint: "Filled in by the send script." }

  - name: settings
    label: Site settings
    files:
      - name: site
        label: Site settings
        file: content/settings/site.json
        format: json
        fields:
          - name: site
            label: Settings
            widget: object
            fields:
              - { name: siteName, label: Site name, widget: string }
              - { name: logo, label: Logo (white PNG), widget: image, required: false }
              - { name: strapline, label: Strapline, widget: string }
              - { name: intro, label: Intro, widget: text }
              - { name: email, label: Contact email, widget: string }
              - name: nav
                label: Navigation
                widget: list
                fields:
                  - { name: label, label: Label, widget: string }
                  - { name: url, label: Link, widget: string }
              - name: social
                label: Social links
                widget: list
                fields:
                  - { name: label, label: Label, widget: string }
                  - { name: url, label: URL, widget: string }
              - name: mailingList
                label: Mailing list
                widget: object
                fields:
                  - { name: heading, label: Heading, widget: string }
                  - { name: text, label: Text, widget: text }
                  - { name: submit, label: Button, widget: string }
                  - { name: note, label: Line under the form, widget: string }
              - name: follow
                label: Follow a film
                widget: object
                hint: "{title} is replaced with the film's name"
                fields:
                  - { name: button, label: Button, widget: string }
                  - { name: heading, label: Panel heading, widget: string }
                  - { name: text, label: Panel text, widget: string }
                  - { name: submit, label: Send button, widget: string }
                  - { name: note, label: Line under the form, widget: string }
                  - { name: done, label: After following, widget: string }
                  - { name: error, label: Bad email message, widget: string }
              - name: emailField
                label: Email fields
                widget: object
                fields:
                  - { name: label, label: Label (read aloud), widget: string }
                  - { name: placeholder, label: Placeholder, widget: string }
                  - { name: privacy, label: Privacy link, widget: string }
              - { name: watchUnavailable, label: "Where to watch: nothing in the visitor's region", widget: string, hint: "{region} is replaced, e.g. the UK" }
              - name: patron
                label: Patron invite
                widget: object
                fields:
                  - { name: heading, label: Heading, widget: string }
                  - { name: text, label: Text, widget: text }
                  - { name: link, label: Link, widget: string }
                  - { name: subject, label: Email subject, widget: string }
              - { name: screener, label: Screener line, widget: string }
              - { name: serviceEnquiry, label: Service enquiry button, widget: string }
              - { name: emailAddressLine, label: Email address under email buttons, widget: string, hint: "{email} is replaced with the contact email" }
              - { name: company, label: Company line (footer), widget: string }
              - name: seo
                label: Default SEO
                widget: object
                fields:
                  - { name: title, label: Title, widget: string }
                  - { name: description, label: Description, widget: text }
                  - { name: image, label: Share image, widget: image, required: false }
      - name: words
        label: Interface words
        file: content/settings/words.json
        format: json
        fields:
          - name: words
            label: Words
            widget: object
            hint: Menus, buttons, headings and the words read aloud to people using screen readers.
            fields:
              - name: nav
                label: Menu
                widget: object
                fields:
                  - { name: menu, label: Menu button on phones, widget: string }
                  - { name: mainLabel, label: Main menu name (read aloud), widget: string }
                  - { name: menuLabel, label: Phone menu name (read aloud), widget: string }
              - name: footer
                label: Footer
                widget: object
                fields:
                  - { name: explore, label: Links heading, widget: string }
                  - { name: exploreLabel, label: Links name (read aloud), widget: string }
                  - { name: follow, label: Social heading, widget: string }
                  - { name: followLabel, label: Social links name (read aloud), widget: string }
                  - { name: contact, label: Contact heading, widget: string }
                  - { name: press, label: Distributors link, widget: string }
                  - { name: privacy, label: Privacy link, widget: string }
              - name: films
                label: Film status and runtime
                widget: object
                fields:
                  - { name: released, label: "Status: released", widget: string }
                  - { name: postProduction, label: "Status: post-production", widget: string }
                  - { name: inDevelopment, label: "Status: in development", widget: string }
                  - { name: outNow, label: Row heading for released films, widget: string }
                  - { name: comingUp, label: Row heading for films not out yet, widget: string }
                  - { name: hoursMinutes, label: Runtime over an hour, widget: string, hint: "{hours} and {minutes} are replaced" }
                  - { name: minutes, label: Runtime under an hour, widget: string, hint: "{minutes} is replaced" }
              - name: cards
                label: Film cards
                widget: object
                fields:
                  - { name: watchNow, label: Watch button, widget: string }
                  - { name: moreInfo, label: More button, widget: string }
                  - { name: close, label: Close (read aloud), widget: string }
              - name: home
                label: Home page
                widget: object
                fields:
                  - { name: watchNow, label: Watch button, widget: string }
                  - { name: aboutFilm, label: About the film button, widget: string }
                  - { name: pauseSlideshow, label: Pause the pictures (read aloud), widget: string }
                  - { name: playSlideshow, label: Play the pictures (read aloud), widget: string }
                  - { name: whereToWatch, label: Where to watch link, widget: string }
              - name: filmPage
                label: Film page
                widget: object
                hint: "{title} is replaced with the film's name"
                fields:
                  - { name: playTrailer, label: Play trailer button (read aloud), widget: string }
                  - { name: trailerButton, label: Trailer picture (read aloud), widget: string }
                  - { name: trailerName, label: Trailer player name (read aloud), widget: string }
                  - { name: pause, label: Pause the background trailer, widget: string }
                  - { name: play, label: Play the background trailer, widget: string }
                  - { name: soundOn, label: Sound on, widget: string }
                  - { name: soundOff, label: Sound off, widget: string }
                  - { name: story, label: Story heading (read aloud), widget: string }
                  - { name: credits, label: Credits heading (read aloud), widget: string }
                  - { name: industry, label: Industry panel heading, widget: string }
                  - { name: runtime, label: "Industry panel: runtime", widget: string }
                  - { name: status, label: "Industry panel: status", widget: string }
                  - { name: pressKit, label: Press kit link, widget: string }
                  - { name: moreFilms, label: More films heading, widget: string }
                  - { name: watchOn, label: Search description ending, widget: string, hint: "{services} is replaced with the services" }
              - name: gallery
                label: Stills
                widget: object
                hint: "{title} is replaced with the film's name"
                fields:
                  - { name: stills, label: Heading for released films, widget: string }
                  - { name: firstLook, label: Heading for films not out yet, widget: string }
                  - { name: open, label: Open a still (read aloud), widget: string, hint: "{n} and {total} are replaced" }
                  - { name: alt, label: Picture description, widget: string }
                  - { name: viewer, label: Viewer name (read aloud), widget: string }
                  - { name: previous, label: Previous (read aloud), widget: string }
                  - { name: next, label: Next (read aloud), widget: string }
                  - { name: close, label: Close (read aloud), widget: string }
              - name: watch
                label: Where to watch
                widget: object
                hint: "{title} is replaced with the film's name"
                fields:
                  - { name: heading, label: Heading, widget: string }
                  - { name: lede, label: Intro, widget: string }
                  - { name: ledeIn, label: Intro with places, widget: string, hint: "{places} is replaced, e.g. the UK and the US" }
                  - { name: and, label: Word between places, widget: string }
                  - { name: allWays, label: All ways to watch link, widget: string }
                  - { name: filterLabel, label: Region buttons name (read aloud), widget: string }
                  - { name: allRegions, label: All regions button, widget: string }
                  - { name: regionHeading, label: Region heading, widget: string, hint: "{place} is replaced, e.g. the UK" }
                  - { name: prices, label: Prices note, widget: string }
                  - { name: aboutFilm, label: Link back to the film, widget: string }
                  - name: regions
                    label: Region names on buttons
                    widget: object
                    fields:
                      - { name: UK, label: UK, widget: string }
                      - { name: US, label: US, widget: string }
                      - { name: Ireland, label: Ireland, widget: string }
                      - { name: Canada, label: Canada, widget: string }
                      - { name: Australia, label: Australia, widget: string }
                      - { name: Worldwide, label: Worldwide, widget: string }
                  - name: places
                    label: Region names in sentences
                    widget: object
                    fields:
                      - { name: UK, label: UK, widget: string }
                      - { name: US, label: US, widget: string }
                      - { name: Ireland, label: Ireland, widget: string }
                      - { name: Canada, label: Canada, widget: string }
                      - { name: Australia, label: Australia, widget: string }
                      - { name: Worldwide, label: Worldwide, widget: string }
              - name: events
                label: Events
                widget: object
                fields:
                  - { name: timeRange, label: From and to, widget: string, hint: "{from} and {to} are replaced" }
              - name: system
                label: System pages
                widget: object
                fields:
                  - name: notFound
                    label: Page not found
                    widget: object
                    fields:
                      - { name: title, label: Tab title, widget: string }
                      - { name: heading, label: Heading, widget: string }
                      - { name: text, label: Text, widget: string }
                      - { name: link, label: Link, widget: string }
                  - name: thanks
                    label: After joining the mailing list
                    widget: object
                    fields:
                      - { name: title, label: Tab title, widget: string }
                      - { name: heading, label: Heading, widget: string }
                      - { name: text, label: Text, widget: string }
                      - { name: link, label: Link, widget: string }
                  - name: badEmail
                    label: Mailing list email not right
                    widget: object
                    fields:
                      - { name: title, label: Tab title, widget: string }
                      - { name: heading, label: Heading, widget: string }
                      - { name: text, label: Text, widget: string }
                      - { name: message, label: Message, widget: string }
                      - { name: link, label: Link, widget: string }
                  - { name: tvCodePlaceholder, label: Example TV code in the box, widget: string }
              - name: contact
                label: Contact page
                widget: object
                fields:
                  - { name: general, label: General heading, widget: string }
                  - { name: emailUs, label: Email button, widget: string }
                  - { name: industry, label: Industry heading, widget: string }
                  - { name: screener, label: Screener button, widget: string, hint: Also on film pages }
                  - { name: screenerSubject, label: Screener email subject, widget: string }
                  - { name: screenerSubjectFilm, label: Screener email subject from a film page, widget: string, hint: "{title} is replaced" }
                  - { name: screenerBody, label: Screener email text, widget: text }
              - name: services
                label: Services pages
                widget: object
                fields:
                  - { name: packages, label: Packages heading (read aloud), widget: string }
              - name: a11y
                label: Read aloud
                widget: object
                fields:
                  - { name: skip, label: Skip to content link, widget: string }
                  - { name: newTab, label: After links that open a new tab, widget: string }
                  - { name: railBack, label: Scroll a row back, widget: string, hint: "{label} is the row's name" }
                  - { name: railOn, label: Scroll a row on, widget: string, hint: "{label} is the row's name" }
              - name: review
                label: Review notes (staging only)
                widget: object
                fields:
                  - { name: toggle, label: Leave a note button, widget: string }
                  - { name: picking, label: While picking, widget: string }
                  - { name: note, label: Note box name (read aloud), widget: string }
                  - { name: placeholder, label: Note box placeholder, widget: string }
                  - { name: save, label: Save button, widget: string }
                  - { name: cancel, label: Cancel button, widget: string }
                  - { name: saving, label: While saving, widget: string }
                  - { name: saved, label: After saving, widget: string }
                  - { name: failed, label: Save failed, widget: string }

  - name: features
    label: Features
    description: Switch features on or off and edit their wording. Each change goes live after the next deploy.
    files:
      - name: login
        label: Sign in
        file: content/features/login.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean }
          - { name: showInNav, label: Show "Sign in" in the menu, widget: boolean }
          - { name: navLabel, label: Menu label, widget: string }
          - { name: signedInLabel, label: Menu label when signed in, widget: string }
          - { name: signedInUrl, label: Where it goes when signed in, widget: string }
          - { name: linkMinutes, label: Link works for (minutes), widget: number, value_type: int }
          - { name: perEmailPerHour, label: Most links per email per hour, widget: number, value_type: int }
          - { name: perIpPerHour, label: Most links per connection per hour, widget: number, value_type: int }
          - { name: heading, label: Heading, widget: string }
          - { name: text, label: Text, widget: text }
          - { name: submit, label: Button, widget: string }
          - { name: sent, label: After sending, widget: string, hint: "{minutes} is replaced" }
          - { name: confirm, label: Button on the link page, widget: string, hint: Only shows if the page can't sign in by itself }
          - { name: signingIn, label: While signing in, widget: string }
          - { name: expired, label: Link expired, widget: string }
          - { name: tooMany, label: Too many links, widget: string }
          - { name: failed, label: Email failed, widget: string }
          - { name: off, label: When switched off, widget: string }
          - name: email
            label: Email
            widget: object
            fields:
              - { name: subject, label: Subject, widget: string }
              - { name: body, label: Body, widget: text, hint: "{link} and {minutes} are replaced" }
      - name: tv
        label: Watch on TV code
        file: content/features/tv.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean }
          - { name: codeMinutes, label: Code works for (minutes), widget: number, value_type: int }
          - { name: perIpPerHour, label: Most codes per connection per hour, widget: number, value_type: int }
          - { name: pollSeconds, label: TV checks every (seconds), widget: number, value_type: int }
          - { name: heading, label: TV heading, widget: string }
          - { name: text, label: TV text, widget: text }
          - { name: goTo, label: Go to line, widget: string, hint: "{link} is replaced with the address" }
          - { name: enter, label: Enter code line, widget: string }
          - { name: expires, label: Under the code, widget: string, hint: "{minutes} is replaced" }
          - { name: scan, label: Under the QR code, widget: string }
          - { name: check, label: TV button, widget: string }
          - { name: signedIn, label: Already signed in, widget: string }
          - { name: yourFilms, label: Your films button, widget: string }
          - { name: tooMany, label: Too many codes, widget: string }
          - { name: off, label: When switched off, widget: string }
          - name: link
            label: Phone page
            widget: object
            fields:
              - { name: heading, label: Heading, widget: string }
              - { name: text, label: Text, widget: text }
              - { name: codeLabel, label: Code field label, widget: string }
              - { name: warning, label: Warning, widget: string, hint: "{email} is replaced" }
              - { name: approve, label: Button, widget: string }
              - { name: approved, label: After approving, widget: string }
              - { name: wrong, label: Wrong code, widget: string }
      - name: account
        label: Member account
        file: content/features/account.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean, hint: "Off: /account/ shows only the line below" }
          - { name: heading, label: Heading, widget: string }
          - { name: signedInAs, label: Line under the heading, widget: string, hint: "{email} is replaced" }
          - { name: off, label: When switched off, widget: string }
          - name: library
            label: Films you can watch
            widget: object
            fields:
              - { name: show, label: Show, widget: boolean }
              - { name: heading, label: Heading, widget: string }
              - { name: empty, label: When there are none, widget: string }
              - { name: watch, label: Watch button, widget: string }
          - name: membership
            label: Membership
            widget: object
            fields:
              - { name: show, label: Show, widget: boolean }
              - { name: heading, label: Heading, widget: string }
              - { name: none, label: When there is no membership, widget: string, required: false, hint: "Leave empty to hide the panel" }
              - { name: plan, label: Plan label, widget: string }
              - { name: status, label: Status label, widget: string }
              - { name: date, label: Date label, widget: string }
              - { name: fallbackName, label: Name for imported members, widget: string, hint: "Used when the plan isn't one of the tiers" }
              - { name: renews, label: Renews, widget: string, hint: "{date} is replaced" }
              - { name: ends, label: Ends, widget: string, hint: "{date} is replaced" }
              - { name: ended, label: Ended, widget: string, hint: "{date} is replaced" }
              - name: statuses
                label: Status words
                widget: object
                fields:
                  - { name: active, label: Active, widget: string }
                  - { name: past_due, label: Payment due, widget: string }
                  - { name: cancelled, label: Cancelled, widget: string }
                  - { name: expired, label: Ended, widget: string }
          - name: purchases
            label: Purchases
            widget: object
            fields:
              - { name: show, label: Show, widget: boolean }
              - { name: heading, label: Heading, widget: string }
              - { name: empty, label: When there are none, widget: string, required: false, hint: "Leave empty to hide the section" }
              - { name: refunded, label: Refunded, widget: string }
              - name: products
                label: Names for each kind of purchase
                widget: object
                hint: "{title} is replaced with the film's name"
                fields:
                  - { name: film, label: Film, widget: string }
                  - { name: bundle, label: Bundle, widget: string }
                  - { name: extras, label: Extras, widget: string }
                  - { name: gift-film, label: Film given as a gift, widget: string, required: false }
                  - { name: gift-bundle, label: Bundle given as a gift, widget: string, required: false }
                  - { name: gift-patron, label: Patron year given as a gift, widget: string, required: false }
          - name: billing
            label: Billing
            widget: object
            hint: Shows only for people who have paid through Stripe
            fields:
              - { name: show, label: Show, widget: boolean }
              - { name: heading, label: Heading, widget: string }
              - { name: text, label: Text, widget: string }
              - { name: button, label: Button, widget: string }
              - { name: failed, label: When billing can't open, widget: string }
          - name: signOut
            label: Signing out
            widget: object
            fields:
              - { name: show, label: Show, widget: boolean }
              - { name: heading, label: Heading (read aloud only), widget: string }
              - { name: text, label: Text, widget: string }
              - { name: button, label: Sign out button, widget: string }
              - { name: everywhere, label: Sign out everywhere button, widget: string }
      - name: patrons
        label: Patron sign up
        file: content/features/patrons.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean, hint: "Turns on the /patron/ page" }
          - name: mode
            label: How people become patrons
            widget: select
            default: email
            options:
              - { label: They email us, value: email }
              - { label: They pay online (Stripe), value: checkout }
          - { name: tiers, label: Tiers to offer, widget: relation, collection: tiers, value_field: "{{slug}}", search_fields: [name], display_fields: [name], multiple: true, hint: "Only tiers marked active show. A tier with a limit hides when full." }
          - { name: recommended, label: Recommended tier, widget: relation, collection: tiers, value_field: "{{slug}}", search_fields: [name], display_fields: [name], required: false }
          - { name: recommendedNote, label: Why it's recommended, widget: string, required: false }
          - { name: inviteOnly, label: By invitation only, widget: boolean, hint: "Paying online needs the invite code below" }
          - { name: inviteCode, label: Invite code, widget: string, required: false, hint: "Share it in your invitation, or as /patron/?code=..." }
          - { name: chooseAmount, label: Let people choose their amount, widget: boolean, hint: "A slider from the price up" }
          - { name: amountMaxTimes, label: Slider goes up to (times the price), widget: number, value_type: float, min: 1 }
          - { name: heading, label: Heading, widget: string }
          - { name: lede, label: Text, widget: text }
          - { name: image, label: Image, widget: image, required: false }
          - { name: perMonth, label: Monthly price label, widget: string }
          - { name: perYear, label: Yearly price label, widget: string }
          - { name: choose, label: Pay button, widget: string }
          - { name: amountLabel, label: Slider label, widget: string }
          - { name: amountNote, label: Line under the slider, widget: string, required: false }
          - { name: emailText, label: Email invitation text, widget: text, required: false }
          - { name: emailButton, label: Email button, widget: string }
          - { name: emailSubject, label: Email subject, widget: string }
          - { name: inviteText, label: Invite code text, widget: string }
          - { name: inviteLabel, label: Invite code field, widget: string }
          - { name: inviteSubmit, label: Invite code button, widget: string }
          - { name: inviteWrong, label: Wrong code, widget: string }
          - { name: allFull, label: When every place is taken, widget: string }
          - { name: unavailable, label: When online payment isn't set up, widget: string }
          - { name: failed, label: When payment can't start, widget: string }
          - { name: joined, label: After paying, widget: text }
          - { name: joinedLink, label: Link after paying, widget: string }
      - name: patrons-upgrade
        label: Patron upgrade
        file: content/features/patrons-upgrade.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean, hint: "Invites people who bought a film to become a patron, on their account page" }
          - { name: tier, label: Tier, widget: relation, collection: tiers, value_field: "{{slug}}", search_fields: [name], display_fields: [name] }
          - { name: discount, label: Off the first year (£), widget: number, value_type: int }
          - { name: couponId, label: Stripe coupon ID, widget: string, required: false, hint: "Optional. Leave empty and a one-off coupon for the discount is made at checkout." }
          - { name: heading, label: Heading, widget: string }
          - { name: text, label: Text, widget: text, hint: "{price} is the reduced price, {was} the usual one" }
          - { name: button, label: Pay button, widget: string }
          - { name: emailButton, label: Email button, widget: string }
          - { name: emailSubject, label: Email subject, widget: string }
      - name: import
        label: Member import (script)
        file: content/features/import.json
        format: json
        fields:
          - { name: enabled, label: Allow importing, widget: boolean, hint: "Needed for scripts/import-members.mjs --apply. Dry runs work either way." }
          - name: who
            label: Who to bring across
            widget: select
            options:
              - { label: People who bought something, value: buyers }
              - { label: Everyone with an account, value: everyone }
          - { name: membershipTier, label: Membership everyone gets, widget: string, required: false, hint: "Leave empty for none" }
          - { name: keepStripeCustomers, label: Keep old Stripe customer IDs, widget: boolean, hint: "Only if the old shop used this Stripe account" }
          - name: rules
            label: What each person gets
            widget: list
            fields:
              - { name: column, label: Column, widget: select, options: [watch_jateb_access, products, coupons, country] }
              - { name: equals, label: Equals, widget: string, required: false }
              - { name: contains, label: Contains, widget: string, required: false }
              - { name: kind, label: Gives, widget: select, options: [membership, film, extras, campaign] }
              - { name: ref, label: "Tier, film or campaign", widget: string }
              - { name: ends, label: Ends (date), widget: datetime, required: false }
      - name: shop
        label: Buy a film
        file: content/features/shop.json
        format: json
        fields:
          - name: owned
            label: When the visitor already owns the film
            widget: object
            fields:
              - { name: watchNow, label: Watch button, widget: string }
          - name: forWho
            label: For me or as a gift
            widget: object
            fields:
              - { name: label, label: Question (read aloud), widget: string }
              - { name: me, label: For me, widget: string }
              - { name: gift, label: As a gift, widget: string }
              - { name: giftButton, label: Button when As a gift is chosen, widget: string }
          - { name: enabled, label: On, widget: boolean, hint: "Shows the offers on film pages. Each film also needs a price and a Vimeo ID." }
          - { name: heading, label: Heading (read aloud), widget: string }
          - name: film
            label: Film offer
            widget: object
            hint: "{title} is replaced with the film's name"
            fields:
              - { name: enabled, label: On, widget: boolean }
              - { name: title, label: Title, widget: string }
              - { name: unit, label: Line under the price, widget: string, required: false }
              - { name: includes, label: What's included, widget: list, required: false }
              - { name: button, label: Button, widget: string }
              - { name: why, label: Why we recommend it (shown when it's the recommended one), widget: string, required: false }
          - name: bundle
            label: Bundle offer (film and extras)
            widget: object
            hint: "{title} is replaced. The film's extras are listed after these lines."
            fields:
              - { name: enabled, label: On, widget: boolean }
              - { name: title, label: Title, widget: string }
              - { name: unit, label: Line under the price, widget: string, required: false }
              - { name: includes, label: What's included, widget: list, required: false }
              - { name: button, label: Button, widget: string }
              - { name: why, label: Why we recommend it (shown when it's the recommended one), widget: string, required: false }
          - { name: recommended, label: Recommended offer, widget: select, options: [{ label: Film, value: film }, { label: Bundle, value: bundle }] }
          - name: chooseAmount
            label: Choose your amount (bundle)
            widget: object
            fields:
              - { name: enabled, label: On, widget: boolean }
              - { name: max, label: Most a buyer can choose (pounds), widget: number, value_type: int }
              - { name: label, label: Label, widget: string }
              - name: messages
                label: Messages as the amount rises
                widget: list
                fields:
                  - { name: from, label: From (pounds), widget: number, value_type: int }
                  - { name: text, label: Message, widget: string }
          - { name: discountCodes, label: Allow discount codes, widget: boolean, hint: "Codes are made in the Stripe dashboard (Products, Coupons)" }
          - { name: reassurance, label: Line under the offers, widget: string }
          - { name: cancelLine, label: Cancel line beside the button, widget: string }
          - { name: checkoutNote, label: Line on the Stripe payment page, widget: string }
          - name: errors
            label: Problems
            widget: object
            fields:
              - { name: unavailable, label: Buying is closed or not set up, widget: string }
              - { name: failed, label: Checkout didn't start, widget: string }
              - { name: amount, label: Amount out of range, widget: string }
          - { name: mockPayments, label: Test payments on staging, widget: boolean, required: false, hint: "When on and no Stripe key is set, buying, gifts and patron sign-ups on staging skip Stripe and act as paid. Never works on fellowshipfilm.com." }
          - name: mock
            label: Test payment words
            widget: object
            fields:
              - { name: note, label: Line by the payment button, widget: string }
              - { name: subject, label: Email subject, widget: string, hint: "{subject} is the usual subject" }
              - { name: emailNote, label: First line of each email, widget: string }
      - name: shop-receipt
        label: Purchase emails
        file: content/features/shop-receipt.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean }
          - { name: subject, label: Subject, widget: string, hint: "{title} is replaced" }
          - { name: body, label: Body, widget: text, hint: "{what}, {title}, {link} (watch page), {signIn}, {email} and {amount} are replaced" }
          - name: what
            label: What they bought
            widget: object
            fields:
              - { name: film, label: Film, widget: string }
              - { name: bundle, label: Bundle, widget: string }
          - { name: replyTo, label: Replies go to, widget: string, required: false }
      - name: shop-notify
        label: Sale notifications
        file: content/features/shop-notify.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean, hint: "An email for every sale, pledge, pre-order and new patron" }
          - { name: to, label: Send to, widget: list }
          - { name: subject, label: Subject for a sale, widget: string, hint: "{what} and {amount} are replaced" }
          - { name: subscriptionSubject, label: Subject for a new subscription, widget: string }
          - { name: body, label: Body, widget: text, hint: "{email}, {amount}, {what}, {discount} and {session} are replaced" }
      - name: gifts
        label: Gift a Film
        file: content/features/gifts.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean, hint: "The gift page for each film on sale, and its links on the watch screen and My films" }
          - { name: discountPercent, label: Discount for people who have watched the film (%), widget: number, value_type: int, hint: "Applies to gifts of a film they have watched to the end. 0 turns it off." }
          - { name: discountPatron, label: Give the discount on patron gifts too, widget: boolean }
          - { name: patronTier, label: Patron tier given, widget: relation, collection: tiers, value_field: "{{slug}}", search_fields: [name], display_fields: [name], hint: "Its price is the gift price. The gift lasts one year from claiming." }
          - { name: expiryMonths, label: Unclaimed gifts run out after (months), widget: number, value_type: int }
          - { name: messageMax, label: Longest message (characters), widget: number, value_type: int }
          - { name: nameMax, label: Longest name (characters), widget: number, value_type: int, hint: "For the giver's name and who a link is for" }
          - { name: recipientsMax, label: Most gifts in one go, widget: number, value_type: int }
          - name: products
            label: What can be given
            widget: object
            fields:
              - { name: film, label: The film, widget: boolean }
              - { name: bundle, label: Film and extras, widget: boolean }
              - { name: patron, label: A year as a patron, widget: boolean }
          - { name: entryLink, label: Link on the watch screen and My films, widget: string }
          - { name: heading, label: Gift page heading, widget: string, hint: "{title} is replaced" }
          - { name: lede, label: Line under the heading, widget: text }
          - { name: back, label: Back to My films, widget: string }
          - { name: siteLink, label: Link to the main website, widget: string }
          - { name: productQuestion, label: Question over the choices, widget: string }
          - name: film
            label: The film choice
            widget: object
            fields:
              - { name: title, label: Name, widget: string }
              - { name: text, label: Line, widget: string, hint: "{title} is replaced" }
          - name: bundle
            label: Film and extras choice
            widget: object
            fields:
              - { name: title, label: Name, widget: string }
              - { name: text, label: Line, widget: string, hint: "{title} is replaced" }
          - name: patron
            label: Patron year choice
            widget: object
            hint: "Shown on the gift page, the claim page and in the email to them. Points follow the patron tier's perks: supporting the films first, watching them as a bonus."
            fields:
              - { name: title, label: Name, widget: string }
              - { name: text, label: What being a patron means, widget: string }
              - { name: points, label: Points, widget: list }
              - { name: note, label: Note on the gift page, widget: string, required: false }
          - { name: price, label: Price, widget: string, hint: "{price} is replaced" }
          - { name: discountedPrice, label: Price with the discount, widget: string, hint: "{price} and {was} are replaced" }
          - { name: discountLine, label: Line when the discount applies, widget: string, hint: "{percent} and {title} are replaced" }
          - { name: discountHint, label: Line when they haven't watched it yet, widget: string, required: false, hint: "{percent} and {title} are replaced. Empty hides it." }
          - { name: deliveryQuestion, label: Question over the delivery choices, widget: string }
          - name: delivery
            label: Delivery choices
            widget: object
            fields:
              - { name: email, label: We email it, widget: string }
              - { name: link, label: They get a link, widget: string }
          - { name: recipientLabel, label: Their email label, widget: string }
          - { name: recipientNote, label: Note under their email, widget: string, required: false }
          - { name: forLabel, label: Who a link is for, widget: string }
          - { name: forNote, label: Note under who a link is for, widget: string, required: false }
          - { name: addPerson, label: Add someone else button, widget: string }
          - { name: remove, label: Remove button, widget: string }
          - { name: total, label: Total for more than one, widget: string, hint: "{count} and {price} are replaced" }
          - { name: messageLabel, label: Message label, widget: string }
          - { name: messageNote, label: Note under the message, widget: string, hint: "{max} is replaced" }
          - { name: messageShared, label: Note under the message when there are several people, widget: string, required: false }
          - { name: personalise, label: Personalise button, widget: string }
          - { name: shareMessage, label: Back to the shared message, widget: string }
          - { name: noMessage, label: Preview when there is no message, widget: string }
          - { name: ownMessage, label: Label of a personal message (for screen readers), widget: string }
          - { name: fromLabel, label: Your name label, widget: string }
          - { name: fromNote, label: Note under your name, widget: string, required: false }
          - { name: button, label: Button, widget: string }
          - { name: reassurance, label: Line under the button, widget: string, hint: "{months} is replaced" }
          - name: checkoutName
            label: Name on the Stripe checkout
            widget: object
            hint: "{title} is replaced"
            fields:
              - { name: film, label: Film, widget: string }
              - { name: bundle, label: Bundle, widget: string }
              - { name: patron, label: Patron year, widget: string }
          - name: what
            label: What they give, in emails and pages
            widget: object
            hint: "{title} is replaced"
            fields:
              - { name: film, label: Film, widget: string }
              - { name: bundle, label: Bundle, widget: string }
              - { name: patron, label: Patron year, widget: string }
          - name: errors
            label: Errors
            widget: object
            fields:
              - { name: unavailable, label: Gift not available, widget: string }
              - { name: payments, label: Payments not set up, widget: string }
              - { name: failed, label: Checkout didn't start, widget: string }
              - { name: recipient, label: Their email missing or wrong, widget: string }
              - { name: duplicate, label: Same email twice, widget: string }
              - { name: count, label: Too many at once, widget: string, hint: "{most} is replaced" }
              - { name: message, label: Message too long, widget: string, hint: "{max} is replaced" }
              - { name: name, label: Name too long, widget: string, hint: "{longest} is replaced" }
              - { name: delivery, label: No delivery chosen, widget: string }
          - name: sent
            label: After paying
            widget: object
            hint: "{what}, {recipient} (all of them), {count} and {expires} are replaced"
            fields:
              - { name: heading, label: Heading, widget: string }
              - { name: emailed, label: When we emailed it, widget: text }
              - { name: link, label: When they asked for a link, widget: text }
              - { name: links, label: When they asked for several links, widget: text }
              - { name: linkLabel, label: Link label, widget: string }
              - { name: linksLabel, label: Link label when there are several, widget: string, hint: "{n} is replaced" }
              - { name: namedLabel, label: Link label when it says who it's for, widget: string, hint: "{name} is replaced" }
              - { name: copy, label: Copy button, widget: string }
              - { name: copied, label: After copying, widget: string }
              - { name: waiting, label: Payment still going through, widget: text }
              - { name: back, label: Back link, widget: string }
          - name: claim
            label: Claim page
            widget: object
            fields:
              - { name: heading, label: Heading, widget: string }
              - { name: headingFor, label: Heading when the link says who it's for, widget: string, hint: "{name} is replaced" }
              - { name: intro, label: Who it's from, widget: string, hint: "{from} (their name, or their email) and {what} are replaced" }
              - { name: messageFrom, label: Over their message, widget: string, hint: "{from} is replaced" }
              - { name: signIn, label: Sign in button, widget: string }
              - { name: signInNote, label: Note under sign in, widget: string }
              - { name: button, label: Claim button, widget: string }
              - { name: invalid, label: Link not found, widget: string }
              - { name: expired, label: Run out, widget: string }
              - { name: claimed, label: Already claimed, widget: string }
              - { name: yours, label: Claimed by them, widget: string }
              - { name: refunded, label: Refunded, widget: string }
              - { name: failed, label: Claim didn't work, widget: string }
              - { name: watch, label: Link to My films, widget: string }
              - { name: account, label: Link to the account (patron gifts), widget: string }
          - name: recipientEmail
            label: Email to the person receiving it
            widget: object
            hint: "{intro}, {from} (their name, or their email), {what}, {title}, {about} (patron gifts), {message}, {link}, {expires} and {amount} are replaced"
            fields:
              - { name: subject, label: Subject, widget: string }
              - { name: body, label: Body, widget: text }
              - { name: message, label: Their message, widget: text, hint: "{message} is replaced. Left out when there is no message." }
          - name: offerEmail
            label: Gift offer email after watching
            widget: object
            hint: "Sent once, the first time someone reaches a film's credits. {title}, {percent} and {link} are replaced. Keep the line about replying to stop."
            fields:
              - { name: enabled, label: On, widget: boolean }
              - { name: subject, label: Subject, widget: string }
              - { name: body, label: Body, widget: text }
          - name: giverEmail
            label: Receipt to the giver
            widget: object
            hint: "{what}, {title}, {gifts} (every person and link), {count}, {expires} and {amount} (the total) are replaced"
            fields:
              - { name: subject, label: Subject, widget: string }
              - { name: emailed, label: Body when we emailed it, widget: text }
              - { name: link, label: Body when they send the link, widget: text }
              - { name: emailedLine, label: Each person in the list (emailed), widget: text, hint: "{recipient} and {link} are replaced" }
              - { name: linkLine, label: Each link in the list, widget: string, hint: "{link} is replaced" }
              - { name: namedLinkLine, label: Each link that says who it's for, widget: text, hint: "{name} and {link} are replaced" }
          - { name: replyTo, label: Replies go to, widget: string, required: false }
      - name: watch
        label: Watch on Fellowship Film
        file: content/features/watch.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean, hint: "The watch page for each film. Off hides buying too." }
          - { name: listLabel, label: Button in the ways to watch, widget: string }
          - { name: listNote, label: Note on that button, widget: string, required: false }
          - { name: geoBlocking, label: Check the visitor's country, widget: boolean, hint: "Uses each film's Licensed in list" }
          - { name: signInMinutes, label: Sign buyers in on return for (minutes), widget: number, value_type: int, hint: "0 means they always sign in by email" }
          - { name: heading, label: Heading, widget: string, hint: "{title} is replaced" }
          - { name: offersLede, label: Line above the offers, widget: string }
          - { name: signInLine, label: Sign in line, widget: string }
          - { name: signInLink, label: Sign in link, widget: string }
          - { name: thanks, label: After paying, widget: string }
          - { name: thanksSignIn, label: After paying, when they need to sign in, widget: string }
          - { name: backing, label: Backers of a film not out yet, widget: string }
          - { name: blocked, label: Not available in their country, widget: string }
          - { name: blockedOther, label: Line above other ways to watch, widget: string }
          - { name: notOnSale, label: Not on sale, widget: string }
          - { name: extrasHeading, label: Extras heading, widget: string }
          - { name: extrasLocked, label: Extras not included, widget: string }
          - { name: download, label: Download button, widget: string }
          - { name: downloadsMissing, label: Downloads not ready, widget: string }
          - { name: playLabel, label: Play button (read aloud), widget: string }
          - { name: play, label: Play button on the watch page, widget: string }
          - { name: continue, label: Play button when part watched, widget: string }
          - { name: watchAgain, label: Play button when watched, widget: string }
          - { name: watched, label: Watched label, widget: string }
          - { name: addExtras, label: Tile offering the extras to film-only buyers, widget: string }
          - { name: addExtrasNote, label: Line under that tile, widget: string, required: false }
          - { name: followNews, label: One-click follow button, widget: string, hint: "{title} is replaced" }
          - { name: followingNews, label: After following, widget: string, hint: "{title} is replaced" }
          - { name: restart, label: Start from the beginning (read aloud), widget: string }
          - { name: minutesLeft, label: Time left, widget: string, hint: "{minutes} is replaced" }
          - { name: extrasLink, label: Extras button, widget: string }
          - { name: rowHeading, label: Heading over the film and extras, widget: string }
          - { name: filmTile, label: Name for the main film in the list, widget: string }
          - { name: back, label: Back to My films (read aloud), widget: string }
          - { name: backToFilm, label: Back from a playing video (read aloud), widget: string, hint: "{title} is replaced" }
          - { name: libraryHeading, label: My films heading, widget: string }
          - { name: libraryEmpty, label: My films when there are none, widget: string }
          - { name: siteLink, label: Link to the main website, widget: string }
          - { name: accountLink, label: Account link, widget: string }
          - name: onTv
            label: Watch on a TV panel
            widget: object
            hint: "{link} is replaced with the TV sign-in address"
            fields:
              - { name: button, label: Button (read aloud), widget: string }
              - { name: heading, label: Heading, widget: string }
              - { name: castTitle, label: Cast heading, widget: string }
              - { name: castText, label: Cast text, widget: text }
              - { name: browserTitle, label: TV browser heading, widget: string }
              - { name: browserText, label: TV browser text, widget: text }
              - { name: approve, label: Button, widget: string }
              - { name: approved, label: After approving, widget: string }
              - { name: wrong, label: Wrong code, widget: string }
              - { name: otherTitle, label: Other device heading, widget: string }
              - { name: otherText, label: Other device text, widget: text }
              - { name: close, label: Close (read aloud), widget: string }
          - name: credits
            label: When the credits start
            widget: object
            hint: "Credits start at the film's own timecode (Films, End credits start at)."
            fields:
              - { name: enabled, label: On, widget: boolean }
              - { name: thanksHeading, label: Heading when the film ends, widget: string, hint: "{title} is replaced" }
              - { name: thanksText, label: Text when a film ends (each film can set its own instead), widget: text, required: false }
              - { name: linkLabel, label: Optional link label (e.g. Follow our next film), widget: string, required: false }
              - { name: linkUrl, label: Optional link address, widget: string, required: false }
          - { name: playerColour, label: "Player control colour (6-digit hex code, no hash)", widget: string, required: false, hint: "Needs a Vimeo Plus plan or higher" }
      - name: terms
        label: Terms and refunds
        file: content/features/terms.json
        format: json
        fields:
          - { name: enabled, label: Show links, widget: boolean, hint: "In the footer and beside buy buttons. The page text is under Pages, Terms and refunds." }
          - { name: footerLabel, label: Footer link, widget: string }
          - { name: offerLabel, label: Link beside buy buttons, widget: string }
      - name: broadcasts
        label: Broadcasts
        file: content/features/broadcasts.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean, hint: "Runs Film Update schedules from the editor. Off: nothing is sent and no rebuilds are started." }
          - { name: sendEmails, label: Send update emails at their scheduled times, widget: boolean, default: false }
          - { name: publishWeb, label: Rebuild the site when an update's website time comes, widget: boolean, default: true }
          - { name: perRun, label: Most emails sent every 5 minutes, widget: number, value_type: int, default: 100 }
          - { name: lateHours, label: Don't start a send more than this many hours late, widget: number, value_type: int, default: 48, hint: "So old updates don't go out by surprise when sending is switched on." }
      - name: newsletter
        label: Mailing list emails
        file: content/features/newsletter.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean, hint: "When off, the send script won't send. Unsubscribe links always work." }
          - { name: fromName, label: From name, widget: string }
          - { name: replyTo, label: Replies go to, widget: string, required: false }
          - { name: dailyCap, label: Most emails per day, widget: number, value_type: int, hint: "Resend's free plan allows 100 a day, counting sign-in and receipt emails." }
          - { name: monthlyCap, label: Most emails per month, widget: number, value_type: int, hint: "Resend's free plan allows 3,000 a month." }
          - { name: batchSize, label: Emails per batch (up to 100), widget: number, value_type: int }
          - { name: footerEveryone, label: Footer for the mailing list, widget: string }
          - { name: footerFilm, label: Footer for followers, widget: string, hint: "{film} is replaced" }
          - { name: unsubscribeLink, label: Unsubscribe link, widget: string }
          - { name: unsubscribeHeading, label: Unsubscribe page heading, widget: string }
          - { name: unsubscribeText, label: Unsubscribe page question, widget: string, hint: "{email} is replaced" }
          - { name: unsubscribeButton, label: Unsubscribe button, widget: string }
          - { name: unsubscribeDone, label: After unsubscribing, widget: string, hint: "{email} is replaced" }
          - { name: unsubscribeInvalid, label: Link not working, widget: string }
      - name: updates
        label: Film updates
        file: content/features/updates.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean }
          - { name: panelCount, label: Updates shown on a film page, widget: number, value_type: int }
          - { name: teaserWords, label: Words shown past the first paragraph of a locked section, widget: number, value_type: int }
          - { name: panelTitle, label: Film page panel title, widget: string }
          - { name: allUpdates, label: Link to all updates, widget: string }
          - { name: listTitle, label: All updates page title, widget: string, hint: "{film} is replaced" }
          - { name: kindUpdate, label: Label for an update, widget: string }
          - { name: kindBehind, label: Label for behind the scenes, widget: string }
          - { name: peopleLabel, label: Before the names of people in an update, widget: string }
          - { name: keepReading, label: Keep reading button, widget: string }
          - { name: followersTitle, label: "Followers box: title", widget: string }
          - { name: followersText, label: "Followers box: text", widget: string, hint: "{film} is replaced" }
          - { name: followButton, label: "Followers box: follow button", widget: string, hint: "{film} is replaced" }
          - { name: patronsTitle, label: "Patrons box: title", widget: string }
          - { name: patronsText, label: "Patrons box: text", widget: string, hint: "{film} is replaced" }
          - { name: buy, label: "Patrons box: buy button", widget: string }
          - { name: buyUrl, label: "Patrons box: buy link", widget: string, hint: "{slug} is the film's address name" }
          - { name: patron, label: "Patrons box: patron button", widget: string }
          - { name: patronUrl, label: "Patrons box: patron link", widget: string }
          - { name: signIn, label: Sign in link, widget: string }
          - { name: signInNote, label: Line before sign in, widget: string }
          - { name: emailSubject, label: Email subject, widget: string, hint: "{film} and {title} are replaced" }
          - { name: emailLocked, label: "Email: line before the link to the rest", widget: string, hint: "{group} is replaced" }
          - { name: emailFollowers, label: "Email: name for followers", widget: string }
          - { name: emailPatrons, label: "Email: name for patrons", widget: string }
          - { name: emailFooter, label: Email footer, widget: string, hint: "{film} is replaced" }
      - name: events
        label: Events
        file: content/features/events.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean }
          - { name: showInNav, label: Show in the menu when events are coming up, widget: boolean }
          - { name: navLabel, label: Menu label, widget: string }
          - { name: showOnHome, label: Show coming events on the home page, widget: boolean }
          - { name: homeCount, label: Events on the home page, widget: number, value_type: int }
          - { name: filmCount, label: Events on a film page, widget: number, value_type: int }
          - name: past
            label: Past events
            widget: select
            options:
              - { label: Hide, value: hide }
              - { label: Short list on the events page, value: list }
          - { name: pastCount, label: Past events listed, widget: number, value_type: int }
          - { name: timeZone, label: Time zone, widget: string, hint: "Leave as Europe/London" }
          - { name: pageTitle, label: Page title, widget: string }
          - { name: pageLede, label: Page intro, widget: string }
          - { name: panelTitle, label: Panel title, widget: string }
          - { name: book, label: Book button, widget: string }
          - { name: allEvents, label: Link to all events, widget: string }
          - { name: pastTitle, label: Past events title, widget: string }
          - { name: none, label: When nothing is planned, widget: string }
          - { name: passed, label: "Event page: once it has passed", widget: string }
          - { name: film, label: "Event page: film label", widget: string }
      - name: analytics
        label: Analytics
        file: content/features/analytics.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean, hint: "Cloudflare Web Analytics: visitor counts, no cookies." }
          - { name: token, label: Site token, widget: string, required: false, hint: "From Cloudflare: Web Analytics, Manage site, the token in the snippet." }
          - { name: privacyLine, label: Line added to the privacy page when on, widget: text }
      - name: people
        label: People profiles
        file: content/features/people.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean, hint: "Each person also needs their own Profile page switch." }
          - { name: linkCredits, label: Link names in credits to profiles, widget: boolean }
          - { name: filmsTitle, label: Films heading (read aloud), widget: string }
          - { name: aboutTitle, label: Bio heading, widget: string, hint: "{name} is replaced" }
          - { name: linksTitle, label: Links label (read aloud), widget: string }
      - name: campaigns
        label: Crowdfunding campaigns
        file: content/features/campaigns.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean, hint: "Campaign pages and the campaign panel on film pages" }
          - { name: previewDrafts, label: Show draft campaigns on the staging site, widget: boolean, hint: "Never on fellowshipfilm.com" }
          - { name: showOnFilmPage, label: Show the campaign on its film's page, widget: boolean }
          - { name: totalsCacheSeconds, label: Totals refresh every (seconds), widget: number, value_type: int }
          - { name: allowPromotionCodes, label: Allow discount codes at checkout, widget: boolean }
          - { name: eyebrow, label: Label above the campaign title, widget: string }
          - { name: draftChip, label: Draft label, widget: string }
          - { name: raisedOf, label: Raised line, widget: string, hint: "{goal} is replaced" }
          - { name: backers, label: Backers, widget: string, hint: "{n} is replaced" }
          - { name: backerOne, label: One backer, widget: string }
          - { name: daysLeft, label: Days left, widget: string, hint: "{days} is replaced" }
          - { name: lastDay, label: Last day, widget: string }
          - { name: ended, label: After the end date, widget: string }
          - { name: upcoming, label: Before the start date, widget: string, hint: "{date} is replaced" }
          - { name: tiersHeading, label: Tiers heading, widget: string }
          - { name: pledgeButton, label: Pledge button, widget: string, hint: "{amount} is replaced" }
          - { name: tierFull, label: Tier full, widget: string }
          - { name: faqHeading, label: Questions heading, widget: string }
          - { name: updatesHeading, label: Updates heading, widget: string }
          - { name: panelButton, label: Button on the film page, widget: string }
          - { name: savedCardNote, label: Note when cards are charged only on success, widget: text }
          - { name: unavailable, label: When payments aren't set up, widget: text }
          - { name: thanksHeading, label: Thank you heading, widget: string }
          - { name: thanksText, label: Thank you text, widget: text }
          - { name: savedThanksText, label: Thank you text (card saved), widget: text }
      - name: pledge
        label: Pledge support
        file: content/features/pledge.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean, hint: "A promise to back a film. No payment." }
          - { name: onlyUnreleased, label: Only films not out yet, widget: boolean }
          - name: films
            label: Per film
            widget: list
            required: false
            hint: "Turn a film off, or change its question and milestones"
            fields:
              - { name: film, label: Film, widget: relation, collection: films, value_field: "{{slug}}", search_fields: [title], display_fields: [title] }
              - { name: enabled, label: On for this film, widget: boolean, default: true }
              - { name: question, label: Open question, widget: string, required: false }
              - { name: milestones, label: Milestones (backers), widget: list, field: { name: step, label: Backers, widget: number, value_type: int }, required: false }
          - { name: eyebrow, label: Label above the heading, widget: string }
          - { name: heading, label: Heading, widget: string, hint: "{title} is the film" }
          - { name: text, label: Text, widget: text }
          - { name: button, label: Button, widget: string }
          - name: interest
            label: Open question
            widget: object
            fields:
              - { name: question, label: Question, widget: string }
              - { name: placeholder, label: Placeholder, widget: string }
          - name: amount
            label: Slider question
            widget: object
            fields:
              - { name: question, label: Question, widget: string }
              - { name: note, label: Note, widget: string }
          - name: scale
            label: Slider
            widget: object
            fields:
              - { name: min, label: Lowest, widget: number, value_type: int }
              - { name: max, label: Highest, widget: number, value_type: int }
              - { name: curve, label: Curve, widget: number, value_type: float, hint: "1 is straight. Higher makes small amounts easier to set (2.6 puts £25 near 10%)." }
              - { name: currency, label: Currency, widget: select, options: [GBP, EUR, USD] }
          - name: messages
            label: Slider messages
            widget: list
            hint: "Shown from each amount up. {title} is the film."
            fields:
              - { name: at, label: From amount, widget: number, value_type: int }
              - { name: text, label: Message, widget: string }
          - name: emailStep
            label: Email question
            widget: object
            fields:
              - { name: question, label: Question, widget: string }
              - { name: note, label: Note, widget: string }
          - name: nameStep
            label: Name question
            widget: object
            fields:
              - { name: question, label: Question, widget: string }
              - { name: placeholder, label: Placeholder, widget: string }
              - { name: anonymous, label: Anonymous choice, widget: string }
          - { name: next, label: Next button, widget: string }
          - { name: back, label: Back button, widget: string }
          - { name: close, label: Close button (read aloud), widget: string }
          - { name: submit, label: Send button, widget: string }
          - { name: confirmByEmail, label: Guests confirm by email before a pledge counts, widget: boolean }
          - { name: linkHours, label: Confirm link works for (hours), widget: number, value_type: int }
          - { name: perIpPerHour, label: Most pledges per connection per hour, widget: number, value_type: int }
          - { name: sent, label: After sending (check email), widget: text }
          - { name: done, label: After pledging (signed in), widget: string, hint: "{name} and {title} are replaced" }
          - { name: nameFallback, label: Name when none is given, widget: string }
          - { name: confirmed, label: After confirming, widget: string, hint: "{name} is replaced" }
          - { name: confirmButton, label: Button on the confirm page, widget: string }
          - { name: expired, label: Link expired, widget: text }
          - { name: failed, label: Email failed, widget: text }
          - { name: tooMany, label: Too many pledges, widget: text }
          - { name: invalid, label: Bad email, widget: string }
          - { name: off, label: When switched off, widget: string }
          - name: email
            label: Confirm email
            widget: object
            fields:
              - { name: subject, label: Subject, widget: string }
              - { name: body, label: Body, widget: text, hint: "{link}, {title}, {amount}, {name} and {hours} are replaced" }
          - name: backers
            label: Backer count
            widget: object
            fields:
              - { name: minToShow, label: Show the count from, widget: number, value_type: int }
              - { name: none, label: Before that, widget: string }
              - { name: one, label: One backer, widget: string }
              - { name: many, label: Several backers, widget: string, hint: "{n} is replaced" }
              - name: wording
                label: Wording
                widget: select
                options:
                  - { label: "Positive only (142 people are backing this film)", value: positive }
                  - { label: "Show how many to the next milestone", value: remaining }
              - { name: remaining, label: How many to go, widget: string, hint: "{left} and {n} are replaced" }
          - name: milestone
            label: Milestone bar
            widget: object
            fields:
              - { name: enabled, label: On, widget: boolean }
              - { name: steps, label: Milestones (backers), widget: list, field: { name: step, label: Backers, widget: number, value_type: int } }
              - { name: label, label: Label, widget: string, hint: "{n} is replaced" }
              - { name: passed, label: After the last milestone, widget: string }
          - name: wall
            label: Backer wall
            widget: object
            fields:
              - { name: enabled, label: On, widget: boolean }
              - { name: size, label: Names shown, widget: number, value_type: int }
              - { name: heading, label: Heading, widget: string }
              - { name: anonymous, label: Anonymous name, widget: string }
          - { name: animateCounter, label: Count up when seen, widget: boolean, hint: "Off for people who ask for less motion" }
          - { name: refreshSeconds, label: Refresh the count every (seconds), widget: number, value_type: int, hint: "0 is off" }
      - name: preorder
        label: Pre-order
        file: content/features/preorder.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean, hint: "Needs Stripe" }
          - name: films
            label: Films
            widget: list
            fields:
              - { name: film, label: Film, widget: relation, collection: films, value_field: "{{slug}}", search_fields: [title], display_fields: [title] }
              - { name: open, label: Open, widget: boolean, default: true }
              - { name: max, label: Highest amount, widget: number, value_type: int }
              - { name: curve, label: Slider curve, widget: number, value_type: float, hint: "1 is straight" }
              - { name: currency, label: Currency, widget: select, options: [GBP, EUR, USD], default: GBP }
              - name: bundles
                label: Bundles
                widget: list
                fields:
                  - { name: id, label: Short name (lowercase, no spaces), widget: string }
                  - { name: name, label: Name, widget: string }
                  - { name: from, label: Price from, widget: number, value_type: int }
                  - { name: summary, label: Summary, widget: string, required: false }
                  - { name: perks, label: Perks, widget: list, required: false }
                  - { name: recommended, label: Chosen first, widget: boolean, default: false }
          - { name: saveCardOption, label: Offer to save a card instead of paying now, widget: boolean }
          - { name: saveCardLabel, label: Save card choice, widget: string }
          - { name: saveCardNote, label: Note at checkout when saving a card, widget: string }
          - { name: allowPromotionCodes, label: Allow discount codes at checkout, widget: boolean }
          - { name: eyebrow, label: Label above the heading, widget: string }
          - { name: heading, label: Heading, widget: string, hint: "{title} is the film" }
          - { name: text, label: Text, widget: text }
          - { name: bundleQuestion, label: Bundle question, widget: string }
          - { name: amountQuestion, label: Amount question, widget: string }
          - { name: amountNote, label: Amount note, widget: string }
          - name: messages
            label: Slider messages
            widget: list
            required: false
            fields:
              - { name: at, label: From amount, widget: number, value_type: int }
              - { name: text, label: Message, widget: string }
          - { name: button, label: Button, widget: string, hint: "{amount} is replaced" }
          - { name: unavailable, label: When payments aren't set up, widget: text }
          - { name: closed, label: When closed, widget: string }
          - { name: thanksHeading, label: Thank you heading, widget: string }
          - { name: thanksText, label: Thank you text, widget: text, hint: "{title} is replaced" }
          - { name: savedThanksText, label: Thank you text (card saved), widget: text }
          - { name: watchLink, label: Link to the film after paying, widget: string }
          - { name: watchPath, label: Film address, widget: string, hint: "{film} is replaced" }
      - name: preorder-perks
        label: Purchase perks
        file: content/features/preorder-perks.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean, hint: "Lists perks on campaign tiers and pre-order bundles" }
          - { name: heading, label: Heading, widget: string }
          - name: films
            label: Perks for every bundle of a film
            widget: list
            required: false
            fields:
              - { name: film, label: Film, widget: relation, collection: films, value_field: "{{slug}}", search_fields: [title], display_fields: [title] }
              - { name: perks, label: Perks, widget: list }
      - name: funnel
        label: Next step invitations
        file: content/features/funnel.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean, hint: "Shows each visitor one next step from what they've done: follow, pledge, pre-order, extras, patron, investing" }
          - { name: investorFrom, label: Offer investing after a pledge of, widget: number, value_type: int }
          - { name: notNow, label: Not now button, widget: string }
          - name: rest
            label: After "Not now"
            widget: object
            hint: "An invitation someone turned down comes back only after this many days and this many return visits to the film. Each further Not now doubles the wait."
            fields:
              - { name: days, label: Wait at least (days), widget: number, value_type: int }
              - { name: visits, label: And at least (return visits), widget: number, value_type: int }
              - { name: maxTimes, label: Stop asking after this many Not nows, widget: number, value_type: int }
          - name: steps
            label: Steps
            widget: object
            fields:
              - { name: follow, label: Follow, widget: object, fields: [{ name: enabled, label: On, widget: boolean }, { name: heading, label: Heading, widget: string }, { name: text, label: Text, widget: text }, { name: button, label: Button, widget: string }, { name: link, label: Link, widget: string, required: false }] }
              - { name: pledge, label: Pledge support, widget: object, fields: [{ name: enabled, label: On, widget: boolean }, { name: heading, label: Heading, widget: string }, { name: text, label: Text, widget: text }, { name: button, label: Button, widget: string }, { name: link, label: Link, widget: string, required: false }] }
              - { name: preorder, label: Pre-order, widget: object, fields: [{ name: enabled, label: On, widget: boolean }, { name: heading, label: Heading, widget: string }, { name: text, label: Text, widget: text }, { name: button, label: Button, widget: string }, { name: link, label: Link, widget: string, required: false }] }
              - { name: perks, label: Extras, widget: object, fields: [{ name: enabled, label: On, widget: boolean }, { name: heading, label: Heading, widget: string }, { name: text, label: Text, widget: text }, { name: button, label: Button, widget: string }, { name: link, label: Link, widget: string, required: false }] }
              - { name: patron, label: Patron, widget: object, hint: "Empty link opens an email to us", fields: [{ name: enabled, label: On, widget: boolean }, { name: heading, label: Heading, widget: string }, { name: text, label: Text, widget: text }, { name: button, label: Button, widget: string }, { name: link, label: Link, widget: string, required: false }] }
              - { name: investor, label: Investing, widget: object, hint: "Empty link opens an email to us", fields: [{ name: enabled, label: On, widget: boolean }, { name: heading, label: Heading, widget: string }, { name: text, label: Text, widget: text }, { name: button, label: Button, widget: string }, { name: link, label: Link, widget: string, required: false }] }
          - name: investor
            label: Investing email
            widget: object
            fields:
              - { name: subject, label: Subject, widget: string, hint: "{title} is replaced" }
              - { name: body, label: Body, widget: text }
      - name: funnel-welcome
        label: Follow welcome
        file: content/features/funnel-welcome.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean, hint: "A short welcome after someone follows a film" }
          - { name: heading, label: Heading, widget: string }
          - { name: line, label: Line, widget: text, hint: "{title} is replaced" }
          - { name: useFilmStills, label: Use the film's stills, widget: boolean }
          - { name: images, label: More images (screenings, on set), widget: list, field: { name: image, label: Image, widget: image }, required: false }
          - { name: maxImages, label: Most images, widget: number, value_type: int }
          - { name: seconds, label: Seconds per image, widget: number, value_type: int }
          - { name: close, label: Close button (read aloud), widget: string }
          - name: sound
            label: Sound
            widget: object
            fields:
              - { name: enabled, label: Offer sound, widget: boolean, hint: "Plays only when the visitor taps it" }
              - { name: file, label: Sound file, widget: file, required: false }
              - { name: label, label: Button, widget: string }
      - name: funnel-tracking
        label: Interest tracking
        file: content/features/funnel-tracking.json
        format: json
        fields:
          - { name: enabled, label: On, widget: boolean, hint: "Records pages and actions for people who have followed a film. Update the privacy page before switching on." }
          - { name: retentionDays, label: Keep records for (days), widget: number, value_type: int }
          - { name: pages, label: Record pages, widget: boolean }
          - { name: actions, label: Record actions, widget: boolean }
