> ## Documentation Index
> Fetch the complete documentation index at: https://gleanfeed.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom portal CSS

> Style your public portal's feedback, roadmap, and changelog pages with your own CSS, using stable selector hooks and theme variables.

Custom CSS is an advanced, optional layer for restyling public portal content after the default portal and [branding](/portal/settings) are working. You write standard CSS against stable selectors, and Glean Feed sanitizes and scopes it before it renders.

## Eligibility

Editing custom CSS requires the **Plus** plan after the subscription's trial period has ended. A workspace that previously unlocked editing with a paid Plus invoice also remains eligible while it stays on Plus.

* A Plus **trial** doesn't unlock editing on its own — it unlocks once your subscription becomes active.
* **Non-Plus** workspaces can open the editor to view and copy any saved CSS, but can't change it.
* If your plan later changes, your **saved CSS keeps rendering** on your portal, but the editor becomes read-only until you're on an eligible plan again.

## Where to find it

Go to **Workspace settings → Branding → Custom CSS**. The section has:

* An **Enable custom CSS** toggle.
* A CSS editor that preserves exactly what you type, including comments and formatting.
* A **Save CSS** button.

Preview mirrors live behavior — there's no separate draft mode. Saving applies your CSS to your live portal immediately.

<Check>
  Save one small, visible rule and refresh **Public Portal**. Confirm the intended content changed
  and unrelated views—such as sign-in and submission dialogs—did not.
</Check>

### The enable/disable toggle

The toggle turns your CSS on and off **without deleting it**. If something looks wrong on your portal, switch **Enable custom CSS** off and save — your portal falls back to default styling while your CSS stays in the editor for you to fix.

<Warning>
  Custom CSS is customer-owned and used at your own risk. It can break your portal's layout or
  readability, and Glean Feed doesn't review or support it. Test your live portal after saving.
  Disabling or clearing your CSS always restores the default appearance.
</Warning>

## Where custom CSS applies

Custom CSS is scoped to your **public portal content pages**, and only those:

| Applies to                                             | Never applies to                                    |
| ------------------------------------------------------ | --------------------------------------------------- |
| Feedback list and detail pages                         | The widget launcher button and your host page       |
| Roadmap                                                | Standalone login and in-portal sign-in dialogs      |
| Changelog                                              | Account settings                                    |
| The same content inside the **embedded widget** iframe | Submission, comment, and reaction forms and dialogs |
|                                                        | The "Powered by Glean Feed" attribution             |

Every selector you write is automatically scoped under the portal content root, so your CSS can't reach the protected views above even if you try to target them.

## What's allowed

Your CSS is sanitized on save. Rendered CSS is scoped; raw CSS is preserved in the editor.

* **Selectors** are scoped to the portal content root automatically. `html`, `body`, and `:root` are treated as aliases for that root, not the whole page.
* **HTTPS assets** are allowed: `url("https://…")` for background images and other assets.
* **`@font-face`** is allowed when every font `url()` is HTTPS.
* **Blocked:** `@import`, non-HTTPS URLs (`http:`, `data:`, and other schemes), and anything that can't be safely scoped.
* **Invalid CSS** won't save — you'll get an error and your last saved CSS stays in place.

## Selector reference

Target these stable `data-gf-*` hooks (as attribute selectors) rather than Glean Feed's internal class names, which can change. Match the scope root as `.gf-custom-css` or `[data-gf-custom-css-root]`.

| Selector                    | Styles                                                                |
| --------------------------- | --------------------------------------------------------------------- |
| `[data-gf-custom-css-root]` | The scope root wrapping all styled content (also `.gf-custom-css`)    |
| `[data-gf-page-header]`     | The eyebrow + title header at the top of each content page            |
| `[data-gf-filter]`          | A filter dropdown (roadmap status, changelog tag)                     |
| `[data-gf-feedback-list]`   | The feedback post list                                                |
| `[data-gf-feedback-card]`   | A single feedback post card                                           |
| `[data-gf-feedback-detail]` | The post header block on a feedback detail page                       |
| `[data-gf-vote]`            | An upvote control                                                     |
| `[data-gf-status]`          | A status badge (icon + label)                                         |
| `[data-gf-comments]`        | The comments list                                                     |
| `[data-gf-comment]`         | A single comment                                                      |
| `[data-gf-roadmap]`         | The roadmap board (all columns)                                       |
| `[data-gf-roadmap-column]`  | A roadmap status column (`data-gf-roadmap-status` carries the status) |
| `[data-gf-roadmap-card]`    | A single roadmap card                                                 |
| `[data-gf-changelog]`       | The changelog timeline                                                |
| `[data-gf-changelog-entry]` | A single changelog entry                                              |
| `[data-gf-changelog-body]`  | The rendered body of a changelog entry                                |
| `[data-gf-changelog-tag]`   | A tag chip on a changelog entry                                       |
| `[data-gf-reactions]`       | The reaction row on a changelog entry                                 |

## Supported theme variables

Reference your portal's theme with `var(--…)` so your CSS follows the accent color and light/dark theme automatically.

| Variable             | Value                           |
| -------------------- | ------------------------------- |
| `--brand`            | Your workspace accent color     |
| `--foreground`       | Primary text color              |
| `--background`       | Page background color           |
| `--card`             | Card / content background color |
| `--muted-foreground` | Secondary / muted text color    |
| `--border`           | Divider and border color        |
| `--radius`           | Base corner radius              |

## Example

A safe starting point — rounder feedback cards, a brand-tinted status badge, and a custom background image over HTTPS:

```css theme={null}
[data-gf-feedback-card] {
  border-radius: 14px;
  border-color: var(--border);
}

[data-gf-feedback-card]:hover {
  border-color: var(--brand);
}

[data-gf-status] {
  font-weight: 600;
}

[data-gf-page-header] {
  background-image: url("https://cdn.example.com/portal-header.png");
  background-size: cover;
  padding: 1.5rem;
  border-radius: var(--radius);
}
```

## Troubleshooting

**Your portal looks broken after saving.** Turn off **Enable custom CSS** under Workspace settings → Branding → Custom CSS and select **Save CSS**. Your portal returns to default styling immediately, and your CSS stays in the editor so you can fix it.

**You want to start over.** Clear the editor and save. An empty stylesheet renders nothing, restoring the default appearance while keeping the feature enabled.

**Your CSS won't save.** The editor rejects invalid CSS, `@import`, and non-HTTPS URLs. Read the error, correct that rule, and save again — your previously saved CSS is untouched until a valid save succeeds.

**A style isn't applying.** Confirm you're targeting a `data-gf-*` selector from the reference above, and that the page is a content page (custom CSS never reaches the launcher, sign-in, account, forms, or the Powered by Glean Feed attribution).
