The built-in styles go first. Yours go last.
Your CSS is written into the same stylesheet as everything your styling settings generate, immediately after it. Equal specificity, lower down. In the cascade, that is the whole feature.
The same declaration, twice. Both carry !important, so the browser keeps the lower one, and the lower one is yours.
02 the cascade
Three rules decide it. Order is already yours.
Nothing here is special to Event Schedule. It is the ordinary CSS cascade, and knowing where your block sits in it is most of the job.
01 order
Later wins a tie
Two declarations of equal specificity: the browser keeps the one written further down. Your block is written after everything the styling settings generate, so you win every tie without doing anything.
02 weight
Match an !important
The body text colour and font family are declared with !important, so a plain rule of yours will not take. Add !important and order takes over again, because yours is the later of two equals.
03 specificity
Specificity still outranks order
An id beats a class no matter where it sits. If a rule refuses to apply, the usual answer is a more specific selector rather than a longer stylesheet.
One honest caveat: two things are written after you. The guest language switcher's own rules sit immediately below your block in the same sheet, and the calendar panel's frame is declared with !important further down the page. Both are in the table below, with what it takes to beat each one. Read the table
03 the rules above yours
Everything you are overriding, listed.
Every rule in that sheet that can get between you and your design. Eight sit above your block, where source order already settles it. Two are written after you, and those two need a lever.
| The rule already in the sheet | Written by | Order | To override |
|---|---|---|---|
| main { height: 100%; } | The guest layout, always | above yours | A plain override. Yours is later, so yours renders. |
| body { min-height: 100vh; display: flex; flex-direction: column; } | The guest layout, always | above yours | A plain override, but worth knowing the body is a flex column before you rework the layout. |
| .gp-banner a { text-decoration: underline; font-weight: 600; } | The guest layout, always | above yours | A plain override. |
| body { color: #33383C !important; } | The guest layout, for both colour schemes | above yours | Repeat the !important. Same weight, lower down, so yours renders. |
| body { font-family: -apple-system, ... !important; } | The typeface setting | above yours | Repeat the !important. You can restyle the type, but you cannot load a new font. |
| body { background-image: linear-gradient(...); } | Background set to Gradient | above yours | A plain override. |
| body { background-color: #hex !important; } | Background set to Solid | above yours | Repeat the !important. |
| body { background-image: url(...); background-size: cover; } | Background set to Image | above yours | A plain override. On your schedule page this one is written for wide screens only. |
| .gp-lang-switcher { background-color: #f3f4f6; } | The guest layout, just after your block | below yours | Written after you, so a plain rule loses. Add !important. The dark-mode variants are .dark-prefixed and already outrank a bare class. |
| .calendar-panel-border { background: rgba(255,255,255,0.95) !important; } | The schedule page, in a later block | below yours | The hardest one. Needs !important AND a more specific selector, such as #calendar-panel-wrapper.calendar-panel-border. |
Scroll the table sideways for the order and the override.
Worth saying plainly: the row about the typeface is a real limit, not a footnote. Custom CSS can restyle type but cannot load it, so the font itself is chosen in the styling settings.
04 what is removed
Seven patterns out. No allowlist.
Your CSS is sanitized when you save it, before it is stored: two preparatory passes, then seven patterns removed. There is no list of approved properties to check your work against, which is the useful part. Grid, custom properties, container queries, clip-path, keyframes and transitions all pass through untouched.
| Step | What it is |
|---|---|
| strip_tags() | Any HTML tag Runs first, so the stylesheet cannot be closed early and a script tag smuggled in behind it. |
| \6a avascript | CSS escape sequences Decoded before anything is matched, so an encoded version of a blocked word is caught too. |
| expression( ) | Legacy script execution An old Internet Explorer hook for running script from a stylesheet. |
| javascript: | Script URLs Removed wherever it appears. |
| @import | Pulling in another stylesheet Which is also why custom CSS cannot import a font sheet. |
| behavior: binding: -moz-binding: | Legacy browser code hooks All three property names are stripped. |
| url(http: https: data: //) | Anything fetched from elsewhere External and protocol-relative URLs and data URIs, so nothing on your page phones out. |
| @font-face { } | Loading a typeface The whole block is removed, not just the source line. |
| @charset | Character-set switching Removed outright. |
Scroll the table sideways for the full description.
Only the matched fragment is deleted, not the rule around it, and what is left over is invalid, so the browser drops it: an @import without its at-keyword is not a rule, and a background-image without its url( is not a value. @font-face is the one pattern removed as a whole block. Everything else in the rule still applies.
05 where it lands
One sheet. Every guest page.
Custom CSS is emitted by the layout every guest-facing page shares, so you write it once and it is already on all of them.
Your schedule page
The calendar or list your visitors land on.
Every event page
One page per event, per date.
The embedded calendar
The iframe on your own website.
The ticket widget
The purchase or RSVP form you embed.
The event request form
Where other people submit to your schedule.
Booking, gallery and feedback pages
Appointments, fan photos, post-event feedback.
What you are selecting
A few of the ids and classes in the guest markup. Treat these as a starting point rather than a published interface: the fastest way to find the right selector is your browser's element inspector on your own page.
- #calendar-app
- The calendar itself
- #calendar-panel-wrapper
- The panel the calendar sits in
- #events-carousel
- The upcoming-events strip
- #month-year-title
- The month heading
- #event-popup
- The day popup
- .gp-banner a
- Links inside your banner message
How much you get
10,000 characters per schedule, which is roughly 300 lines of ordinary CSS. For scale, here is what typical work costs against that ceiling.
06 everything else
The parts nobody tells you.
The visual settings do the heavy lifting first
FreeAccent colour, typeface, a solid or gradient or image background, the header style and whether events show as a calendar or a list are all free and all ungated. They are what write the rules above your block.
Which means the sensible order is: get as far as you can with the controls, then spend your CSS on the things they do not reach.
The preview will not show it
The preview panel beside the styling settings redraws from the colour, typeface, background and header fields. It never reads the CSS box. Save, then open your own schedule page in another tab and reload as you go.
It travels with your backup
FreeYour stylesheet is part of the schedule export, and it is sanitized again on the way back in. Moving a schedule between installs does not mean re-authoring it.
Selfhosted installs have it already
The plan check returns true for every schedule on an install that is not the hosted service, so Custom CSS is simply on. Nothing to buy, nothing to switch on.
The sanitizer still runs there, which is deliberate: it also catches the paste that would have broken your own page. How selfhosting works
It goes into the embeds too
ProThe embedded calendar and the ticket widget are rendered by the same guest layout, so your sheet is inside the iframe on your own site without a second copy to maintain.
What it pairs with
CSS decides how the page looks. Two other settings decide whose page it reads as: removing the Event Schedule footer line, on Pro, and serving the whole thing from your own domain, on Enterprise.
07 the plan
Five dollars a month, or selfhost it.
On Free
FreeThe whole visual styling suite. Accent colour, typeface, background, header style, layout, and the schedule itself with calendar sync, followers and newsletters.
On Pro
ProCustom CSS, alongside ticketing with QR check-in, event graphics, the ticket widget and the removal of our footer line. One price for all of it.
Selfhosted
Every schedule on your install has it, because the plan check is true off the hosted service. The app is open source and the styling is not held back.
Being straight about the edge case: on the hosted service, a stylesheet is only rendered while the schedule is on Pro. If a plan lapses your CSS stays saved and read-only, and the page falls back to your styling settings until the plan is active again.
Free forever. Upgrade when you're ready.
Zero platform fees on ticket sales. You only pay Stripe's processing fee.
See all plans08 questions
Frequently asked questions
What designers ask before they start writing.
How do I add Custom CSS to my schedule?
Edit your schedule, open the Style section and then the Advanced tab. Custom CSS is a plain text area there. It saves with the rest of your styling settings and applies from the next page load.
Where does my CSS land in the cascade?
In the same style block as the rules your styling settings generate, immediately after them. Specificity is equal, so a tie goes to the later rule, and the later rule is yours. Three things need more than source order from you: the body colour and font family, which the guest layout declares with !important, the guest language switcher, whose rules are written just after your block, and the calendar panel frame, which is declared further down the page and also needs a more specific selector.
Is Custom CSS secure?
Your CSS is sanitized on save, before it is stored. HTML tags are stripped first, then CSS escape sequences are decoded so an encoded blocked word cannot slip through, and then seven patterns are removed: expression(), javascript:, @import, behavior, binding and -moz-binding, url() pointing at http, https, a data URI or a protocol-relative //, @font-face blocks, and @charset. Everything else passes: there is no property allowlist.
Can I load a web font with Custom CSS?
No. @font-face blocks and @import are both removed, and url() cannot reach another server, so a stylesheet cannot fetch a font file. Choose your typeface in the font setting, which loads it properly, then use Custom CSS for size, weight, spacing and line height.
Can I use Custom CSS with the built-in styling options?
Yes, and that is the intended order. Set the accent colour, typeface, background and header style with the visual controls, all of which are free, and use Custom CSS for the details they do not reach: spacing, borders, shadows, transitions and animations. Your CSS is the last layer, not a replacement for the first one.
How much CSS can I save?
10,000 characters per schedule, which is roughly 300 lines of ordinary CSS. It is stored with the schedule and travels with your backup export, where it is sanitized again on import.
Does the live preview show my Custom CSS?
No. The preview panel on the edit page redraws from the colour, typeface, background and header fields, and never reads the CSS box. Save, then open your schedule page to see your CSS applied, which is also how visitors will see it.
Which plan includes Custom CSS?
Pro, and every schedule on a selfhosted install. Free plans keep the whole visual styling suite: accent colour, typeface, solid, gradient or image backgrounds, header style and the list or calendar layout. If a hosted schedule stops being Pro, the CSS stays saved and stops rendering until the plan is active again.
Claim the name. Then write the sheet.
Publishing a schedule is free forever. Custom CSS arrives with Pro at five dollars a month, and it is included on every selfhosted install.
No credit card required