# Layout and theming

> Size the mindset-agent element, put it in a floating bubble or a side panel, and match its colors and dark mode to your app.

After this page the chat panel sits where you want it in your app, at the size you want, in your colors, in light and dark mode.

It applies to the drop-in element. With the UI-less client the interface is yours, so layout and styling are too.

## How the element sizes itself

`<mindset-agent>` is a block element. It takes the full height of its parent, with a minimum of 24rem.

| Built-in rule | What it means for you |
|---|---|
| `display: block` | It takes the full width of its container, like a `div` |
| `block-size: 100%` | It fills its parent's height, when the parent has one |
| `min-block-size: 24rem` | Inside a parent with no set height, you get a 24rem panel |
| `font-size: 16px` and `line-height: 1.5` | Your page's text size doesn't reflow the transcript |
| `[hidden]` hides it | The `hidden` attribute works as on any element |

Every one of these is overridable. A rule in your own stylesheet on `mindset-agent` beats the element's built-in rules, so you can set a fixed height, `display: flex`, or anything else.

The usual reason a panel looks broken is a parent with no height. Give the element itself a height, or give its parent one.

```css
/* A fixed panel */
mindset-agent {
  height: 640px;
}
```

```css
/* A full-height side panel in a flex layout */
.app {
  display: flex;
  height: 100vh;
}

.app main {
  flex: 1;
  overflow: auto;
}

.app aside {
  width: 400px;
  display: flex;
  flex-direction: column;
}

.app aside mindset-agent {
  flex: 1;
  min-height: 0;
}
```

## A floating help bubble

This is a complete page with a round button in the corner that opens the agent in a panel above it. The element is configured the first time the user opens the panel, because `configure()` asks your backend for a session.

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Billing</title>
    <style>
      .help-button {
        position: fixed;
        right: 24px;
        bottom: 24px;
        width: 56px;
        height: 56px;
        border: 0;
        border-radius: 50%;
        background: rgb(124 58 237);
        color: white;
        font-size: 24px;
        cursor: pointer;
      }

      .help-panel {
        position: fixed;
        right: 24px;
        bottom: 96px;
        width: min(400px, calc(100vw - 48px));
        height: min(640px, calc(100vh - 128px));
        border-radius: 12px;
        overflow: hidden;
        box-shadow: 0 12px 32px rgb(0 0 0 / 0.2);
      }

      .help-panel mindset-agent {
        height: 100%;
        min-height: 0;
      }
    </style>
  </head>
  <body>
    <button class="help-button" type="button" aria-expanded="false" aria-controls="help">?</button>

    <div class="help-panel" id="help" hidden>
      <mindset-agent agent="billing-help"></mindset-agent>
    </div>

    <script src="https://eu.mindset.ai/sdk/mindset-agent.js"></script>
    <script>
      const button = document.querySelector(".help-button");
      const panel = document.querySelector("#help");
      const agent = panel.querySelector("mindset-agent");
      let configured = false;

      button.addEventListener("click", () => {
        const opening = panel.hidden;
        panel.hidden = !opening;
        button.setAttribute("aria-expanded", String(opening));

        if (opening && !configured) {
          configured = true;
          agent.configure({
            getSession: async () => {
              const r = await fetch("/api/session");
              if (!r.ok) throw new Error("Could not start a session");
              return r.json();
            },
            conversationList: true,
          });
        }
      });
    </script>
  </body>
</html>
```

Hiding the panel doesn't stop the conversation. Closing and reopening it shows the same conversation. `/api/session` is the endpoint from [Put an agent on your page](https://docs4.mindset.ai/docs/sdk/put-an-agent-on-your-page).

To avoid downloading the script until the user opens the panel, load it on the first click. [Use it with React and Vue](https://docs4.mindset.ai/docs/sdk/use-it-with-react-and-vue#load-it-only-when-it-is-needed) shows how.

## Dark mode

The element ships a light set of colors and a dark set. Add `class="dark"` to the tag for the dark set.

```html
<mindset-agent agent="billing-help" class="dark"></mindset-agent>
```

To follow the user's system setting, toggle the class from script:

```javascript
const agent = document.querySelector("mindset-agent");
const darkQuery = window.matchMedia("(prefers-color-scheme: dark)");

function applyScheme() {
  agent.classList.toggle("dark", darkQuery.matches);
}

applyScheme();
darkQuery.addEventListener("change", applyScheme);
```

If your app has its own dark mode switch, toggle the class wherever you toggle your own.

## Match your colors

Colors are CSS custom properties, called channels, set on the element. A rule in your stylesheet beats the element's defaults.

Most channels take three numbers for red, green and blue, from 0 to 255, separated by spaces. A handful take a full color value with transparency instead, such as `rgba(255, 255, 255, 1)`. `--ch-panel` and `--ch-overlay` are the two you are most likely to set. Giving a channel the wrong format gives an invalid color, and that part of the panel loses its color. [The element reference](https://docs4.mindset.ai/docs/sdk/the-mindset-agent-element#theming) lists every channel and which ones take full values.

These are the channels that change most of what a user sees:

| Channel | What it colors | Format |
|---|---|---|
| `--ch-page` | The page background behind the conversation | `R G B` |
| `--ch-panel` | Panel surfaces | `rgba(...)` |
| `--ch-card` | Cards, including the cards and widgets the agent shows | `R G B` |
| `--ch-surface` | Secondary, slightly recessed surfaces | `R G B` |
| `--ch-input` | Input fields | `R G B` |
| `--ch-text-heading`, `--ch-text-primary`, `--ch-text-secondary` | Text, from strongest to softest | `R G B` |
| `--ch-edge` | Borders | `R G B` |
| `--ch-accent` | Accent highlights, accent borders and focus rings | `R G B` |
| `--ch-on-accent` | Text drawn on the accent color | `R G B` |
| `--ch-btn-primary` | Primary buttons | `R G B` |
| `--ch-overlay` | The scrim behind dialogs | `rgba(...)` |

A theme for the billing app's violet brand, in both modes:

```css
mindset-agent {
  --ch-accent: 124 58 237;
  --ch-on-accent: 255 255 255;
  --ch-btn-primary: 124 58 237;
  --ch-page: 250 250 252;
  --ch-panel: rgba(255, 255, 255, 1);
}

mindset-agent.dark {
  --ch-accent: 167 139 250;
  --ch-on-accent: 24 24 27;
  --ch-btn-primary: 139 92 246;
  --ch-page: 24 24 27;
  --ch-panel: rgba(39, 39, 42, 1);
}
```

Your overrides apply whatever the mode. A rule on plain `mindset-agent` also wins in dark mode, so give dark mode its own rule on `mindset-agent.dark`, as above.

The channel list can grow as the interface changes. A channel you don't set keeps its default.

## Fonts

The element uses the Inter typeface, which it loads from your Mindset host (`https://YOUR-MINDSET-HOST/fonts/`). If that request is blocked, for example by a content security policy without the host in `font-src`, the element falls back to the system font. Nothing else breaks. See [Content security policy](https://docs4.mindset.ai/docs/sdk/content-security-policy).

The font isn't one of the theming channels.

## What can go wrong

| What you see | Cause and fix |
|---|---|
| The panel is 24rem tall whatever you do to its container | The container has no height of its own. Set a height on the element, or on a parent all the way up |
| The panel overflows its container | The container is shorter than 24rem. Set `min-height: 0` (or a smaller `min-height`) on the element |
| Part of the panel has no background, or the default color | A channel got a value in the wrong format. `--ch-panel` and `--ch-overlay` need a full `rgba()` value. Most others need three numbers, without `rgb()` |
| Dark mode shows your light colors | You set channels on `mindset-agent` but not on `mindset-agent.dark` |
| Text is in a system font | The font files didn't load from your Mindset host. Check your `font-src` |
| Your page's CSS doesn't change the chat | That's expected. The element renders in a shadow root. Use channels |

## Related

- [The mindset-agent element](https://docs4.mindset.ai/docs/sdk/the-mindset-agent-element) for every channel, attribute and method.
- [Use it with React and Vue](https://docs4.mindset.ai/docs/sdk/use-it-with-react-and-vue) for frameworks and lazy loading.
