# Goal bar styling

> Class names, state attributes, layout rules and CSS custom properties for the AndOr order goal bar, with Dawn and Horizon examples.

Source: https://backtrackhq.com/docs/widgets/goal-bar/styling/

This page is for theme developers. It lists the classes, states and CSS
custom properties of the goal bar, `<andor-goal class="andor-goal">`.

The widget comes from the **AndOr Order goal** block, the pasted
`<andor-goal>` tag and the cart drawer copy. It uses AndOr's widget
styles. Liquid prints a skeleton at the finished
size, and a script prints the words, fill and markers into it.

## What each token changes

The numbers on the diagram match the table. The diagram is a simplified drawing. The full list of tokens is below.
For every layout the block offers, see [Layouts](https://backtrackhq.com/docs/widgets/goal-bar/#layouts).
(Diagram: The goal bar in the Horizontal layout with three steps, the first one reached)
1. `--andor-goal-text-color`: the sentence
2. `--andor-goal-track-background`: the empty track
3. `--andor-goal-fill-color`: the fill
4. `--andor-goal-marker-size`: each step's circle
5. `--andor-goal-next-color`: the next step
6. `--andor-goal-step-color`: later steps
7. `--andor-goal-border-color`: the box border
8. `--andor-goal-radius`: box corners

## How precedence works

Put your CSS in your theme's stylesheet or in the app embed's
**Custom CSS** box. To see which value wins, read
[Which value wins](https://backtrackhq.com/docs/developers/tokens/#which-value-wins).

What this means for the goal bar:

- **Bar color** is written inline on the host as `--andor-goal-accent`,
  but only when the merchant changed it from `#c0392b`. See
  [Change an inline color](#change-an-inline-color).
- **Show reward icons** and **Icon position** are inline too, and only
  when changed from the default.

> **Tip:** Change `--andor-goal-step-font-size` to scale the whole bar.
> The markers are drawn in the bar's own `em`, so they scale with it.

## Parts

| Class | What it is |
|---|---|
| `.andor-goal` | the host: the bordered box |
| `.andor-goal__text` | the sentence, a `p` |
| `.andor-goal__unlocked` | "You've unlocked 10% off your order" |
| `.andor-goal__remaining` | "You're $20.00 away from 20% off your order" |
| `.andor-goal__bar` | the track and the steps (a size container) |
| `.andor-goal__track` | the track (`role="progressbar"`) |
| `.andor-goal__fill` | the filled part of the track |
| `.andor-goal__steps` | the list of steps, two tiers or more |
| `.andor-goal__step` | one step: circle `::before`, check `::after` |
| `.andor-goal__step-reward` | the reward line, "20% off" |
| `.andor-goal__step-at` | the threshold line, "$100.00" |
| `.andor-goal__icon` | the reward icon beside the label |
| `.andor-goal__note` | the line a kept bar shows in its place |

Products suggested under the bar have their own parts. See
[Goal suggestions styling](https://backtrackhq.com/docs/widgets/goal-suggestions/styling/).

## States and data attributes

| Attribute or class | On | Meaning |
|---|---|---|
| `data-andor-progress` | host | `locked`, `unlocked` or `won`, from the cart |
| `data-andor-goal-reached` | `.andor-goal__step` | this step is reached |
| `.andor-goal--vertical` | host | the **Stacked list** layout |
| `data-andor-skeleton` | host | not printed yet: shimmers, sized |
| `data-andor-goal-settled` | host | printed from a real cart. The fill slides |
| `data-andor-kept="note"` | host | gone mid-visit: one line says why |
| `data-andor-kept=""` | host | a drawer copy holding its room: shimmers |
| `data-andor-goal-clone` | host | the copy in the cart drawer |
| `data-andor-state` | host | `active` or `hidden` (written on every widget host) |
| `data-drawer="only"` | pasted tag | feeds the drawer only |
| `data-icons="false"` | pasted tag | no reward icons on this bar |
| `data-icon-position` | pasted tag | `label`: icons beside the labels |
| `data-andor-icon` | `.andor-goal__icon` | `off`, `ship` or `gift` |
| `data-andor-icon` | `.andor-goal__step` | the same, icon in the circle |
| `hidden` | a text span | that sentence does not apply now |

`data-andor-progress` values:

| Value | Meaning |
|---|---|
| `locked` | the cart has not reached a step yet |
| `unlocked` | the cart reached a step |
| `won` | the top step is reached |

The next step, the one the sentence names, has no attribute of its own.
It is the first step without `data-andor-goal-reached`:

```css
.andor-goal__step:first-child:not([data-andor-goal-reached]),
[data-andor-goal-reached] + .andor-goal__step:not([data-andor-goal-reached]) {
  font-weight: 600;
}
```

## Layout

- The steps are equal columns. Each circle sits at the center of its
  column, whatever the amounts. With 3 steps, the circles sit at 1/6,
  3/6 and 5/6 of the track.
- The reward and the amount are centered under their circle.
- The fill meets each circle exactly at its amount, and moves in a
  straight line between two circles. Example: steps at $50 and $100 sit
  at 25% and 75%, so a $70 cart fills 45%.
- One step has no circle. Its fill is the cart total over the amount.
- Only **Stacked list** (or `data-orientation="vertical"`) stacks the
  steps. On a narrow bar (below a 24rem track), a horizontal bar keeps
  its row and the labels shrink and may wrap.

The bar is a size container named `andor-goal`, so your CSS can use it:

```css
@container andor-goal (max-width: 24rem) {
  .andor-goal__step-at { display: none; }
}
```

## Custom properties

| Property | Default | Controls |
|---|---|---|
| `--andor-goal-accent` | block setting, else `--andor-color-accent` | fill, reached, next |
| `--andor-goal-space-block-start` | `0` | margin above |
| `--andor-goal-space-block-end` | `0` | margin below |
| `--andor-goal-padding` | `1em 1.25em` | box padding |
| `--andor-goal-border-width` | `1px` | box border width |
| `--andor-goal-border-color` | `--andor-color-border`, 12% ink | box border color |
| `--andor-goal-radius` | `0.5em` | box corners |
| `--andor-goal-background` | `transparent` | box background |
| `--andor-goal-color` | `inherit` | text color |
| `--andor-goal-font-size` | `inherit` | everything's base size |
| `--andor-goal-text-space` | `0.75em` | space under the sentence |
| `--andor-goal-text-color` | `inherit` | sentence color |
| `--andor-goal-text-font-size` | `inherit` | sentence size |
| `--andor-goal-text-font-weight` | `600` | sentence weight |
| `--andor-goal-note-color` | the sentence color | a kept bar's line |
| `--andor-goal-note-font-weight` | `inherit` | a kept bar's line weight |
| `--andor-goal-step-font-size` | `0.85em` | step labels and markers |
| `--andor-goal-step-color` | `--andor-color-muted`, `#6d7175` | later steps |
| `--andor-goal-next-color` | `inherit` | the next step |
| `--andor-goal-step-reward-font-weight` | `600` | the reward line |
| `--andor-goal-track-height` | `6px` | track thickness |
| `--andor-goal-track-radius` | `--andor-radius`, `4px` | track corners |
| `--andor-goal-track-background` | 8% ink | empty track |
| `--andor-goal-fill-color` | the accent | the fill |
| `--andor-goal-marker-size` | `1.4em` | marker circle |
| `--andor-goal-marker-border-width` | `2px` | marker ring |
| `--andor-goal-marker-background` | `#fff` | marker inside |
| `--andor-goal-tick` | `--andor-color-muted`, `#8c9196` | later rings, circle icons |
| `--andor-goal-check` | `--andor-color-on-accent`, `#fff` | check, or reached icon |
| `--andor-goal-row-height` | `3.6em` | one row when stacked |
| `--andor-goal-drawer-gutter` | the drawer inset, `0` | drawer copy's sides |
| `--andor-goal-icons` | `inline-block` | `none` hides the icons |
| `--andor-goal-icon-size` | `1.15em` | icon width and height |
| `--andor-goal-icon-color` | `currentColor` | icon color |
| `--andor-goal-dot-icon-size` | `calc(var(--andor-goal-dot) * 0.6)` | icon inside the circle |

"Ink" means black at that opacity.

### Change an inline color

The block writes **Bar color** inline on the host
(`style="--andor-goal-accent: ..."`) when you changed it from the
default. An inline custom property beats a stylesheet rule on the same
element. To recolor from CSS, set the part's own property
(`--andor-goal-fill-color`), or set the accent on a child:

```css
andor-goal .andor-goal__bar {
  --andor-goal-accent: #0b6b4f;
}
```

Left at the default color, the inline value is
`var(--andor-color-accent)`, so a `:root` rule reaches it:

```css
:root {
  --andor-color-accent: #0b6b4f;
}
```

### Reward icons

Each icon is a CSS mask painted in its line's color. With **Inside
circle**, the step's `::after` paints the icon at 60% of the circle
(`--andor-goal-dot-icon-size`). Size it like any part:

```css
andor-goal {
  --andor-goal-dot-icon-size: 0.8em;
}
```

`--andor-goal-icons: none` hides every icon, like the block checkbox.

## Examples

Dawn:

<p class="docs-code-file">assets/base.css</p>

```css
andor-goal {
  --andor-goal-border-color: rgba(var(--color-foreground), 0.12);
  --andor-goal-radius: var(--inputs-radius, 0);
  --andor-goal-step-color: rgba(var(--color-foreground), 0.65);
  --andor-goal-track-background: rgba(var(--color-foreground), 0.08);
  --andor-goal-marker-background: rgb(var(--color-background));
  --andor-goal-fill-color: rgb(var(--color-button));
}
```

Horizon:

<p class="docs-code-file">assets/base.css</p>

```css
andor-goal {
  --andor-goal-border-color: var(--color-border);
  --andor-goal-radius: var(--style-border-radius-inputs, 8px);
  --andor-goal-step-color: color-mix(in srgb,
    var(--color-foreground) 65%, #0000);
  --andor-goal-marker-background: var(--color-background);
  --andor-goal-fill-color: var(--color-primary-button-background);
}
```

> **Caution:** Never force a hidden part back on. A hidden bar or part
> carries `hidden` and an inline `display: none`. A rule like
> `andor-goal { display: block }` can show a goal that no longer applies.
