Anki Progression [Support Thread]

Progression bar
Support thread for the Anki Progression [Lτ] add-on, which adds a versatile and customizable progress bar to Anki. Key distinctions from other progress bar add-ons:

Stats:

  • Allows distinguishing between daily reviews rated Again, Hard, Good, and Easy
  • Allows differentiation between New, Learning, and Review cards, as well as further distinction between Learning and Relearning states.
  • Accurately calculates New cards count for all decks, factoring in daily limits of each subdeck in the deck tree
  • Can separately display Learning/Relearning cards that are ready for review and those that are on cooldown for the current learning step
  • Estimates future intraday reviews for new, learning and relearning cards in accordance with learning and relearning steps in deck settings

Customization:

  • All categories described above can be freely disabled, grouped, merged, and reordered for a complete control over the level-of-detail of the displayed progress (the instructions will be provided below, in a separate post)
  • The whole setup is controlled directly with CSS, making every display property (including overall size, position, colors, animations, etc.) freely adjustable. In particular, it also allows breaking the progress bar into sections, wrapping the sections across several lines (sample presets for different styles can be found below)
  • Different appearances can be set up for different Anki windows (for instance, the progress bar can be displayed in a minimal style during the review, while providing a detailed breakdown of complete stats in the main deck screen)
  • The bar is embedded directly into the webview, allowing card templates to tailor the progress visualization, incorporating it seamlessly into their design (example).

What the add-on doesn’t do (so far):

  • Count manually rescheduled cards and cards in filtered decks
  • Take into account non-monotonic learning steps
  • Future steps calculations are based on estimates and can slightly deviate from the actual counts, especially when sibling burying is enabled in the settings. All estimates are convergent, however, so they should not display any residual reviews when non left
  • The learn-ahead timer is not applied when differentiating between ready-for-review and on-cooldown cards

Progress bar presets

1. Minimal

The most basic setup displaying the total reviews done in the current day vs total reviews due at the moment

Minimal progress bar

Preset CSS
.prog-segment {
    background: var(--canvas-elevated);
}
  
.prog-segment.done {
    background: var(--button-primary-bg);
}
  
.prog-segment.cooldown,
.prog-segment.future {
    display: none;
}

1A. Minimal (strict)

Does not count Again (on all cards) and Hard (on (re)learned cards) towards the daily progress. Additionally displays cards which currently are in a (re)learning phase, but which are not due yet:

Strict minimal progress bar

Preset CSS
.prog-segment {
    background: var(--canvas-elevated);
}

.prog-segment.done {
    background: red;
}

.prog-segment.again,
.prog-segment.learning.hard {
    display: none;
}

.prog-segment.todo {
    opacity: 0.6;
}

.prog-segment.cooldown {
    background: var(--border-subtle);
}

.prog-segment.future {
    display: none;
}

2. Ratings

Splits the completed portion of the progress bar into sections for each of the Again, Hard, Good, and Easy card ratings. The colors correspond to the Anki’s Stats screen. Additionally hints at the number of the future steps for all currently (re)learned cards.

Ratings progress bar

Preset CSS
#lt-progress-bar {
    top: .25rem;
}

.prog-segment {
    height: 1rem;
}

.prog-segment.done {
    background: var(--rate-color);
}

.prog-segment.todo {
    background: var(--canvas-elevated);
}

.prog-segment.cooldown,
.prog-segment.future {
    background: var(--canvas);
}

.prog-segment.again {
    order: -4;
}
.prog-segment.hard {
    order: -3;
}
.prog-segment.good {
    order: -2;
}
.prog-segment.easy {
    order: -1;
}

2A. Ratings (AnkiDroid)

Similar setup but with the color scheme borrowed from AnkiDroid rating buttons:

AnkiDroid ratings progress bar

Preset CSS
#lt-progress-bar {
    top: .25rem;
    box-shadow: 0px 2px 1px -1px rgba(20,20,20,.12),0px 1px 1px 0px rgba(20,20,20,.06),0px 1px 3px 0px rgba(20,20,20,.04);
}

.prog-segment {
    height: 1rem;
}

.prog-segment.done {
    background: var(--rate-color);
}

.prog-segment.todo {
    background: var(--canvas-elevated);
}

.prog-segment.cooldown {
    background: var(--canvas);
}

.prog-segment.future {
    display: none;
}

.prog-segment.again {
    --rate-color: color-mix(in lab, var(--ad-again) 80%, var(--ad-again-text));
    order: -4;
}
.prog-segment.hard {
    --rate-color: color-mix(in lab, var(--ad-hard) 80%, var(--ad-hard-text));
    order: -3;
}
.prog-segment.good {
    --rate-color: color-mix(in lab, var(--ad-good) 80%, var(--ad-good-text));
    order: -2;
}
.prog-segment.easy {
    --rate-color: color-mix(in lab, var(--ad-easy) 80%, var(--ad-easy-text));
    order: -1;
}

3. States

Splits both the completed (vivid) and pending (faint) sections of the progress bar into segments for each of the three primary New, Learn, Due card categories. The colors correspond to Anki’s review counters:

States progress bar

Preset CSS
#lt-progress-bar {
    top: 4px;
}

.prog-segment.prog-segment {
    order: 0;
    height: 7px;
}

.prog-segment.done {
    background: var(--state-color);
}

.prog-segment.todo {
    background: color-mix(in lab, var(--state-color) 30%, var(--canvas-elevated));
}

.prog-segment.cooldown,
.prog-segment.future {
    display: none;
}

.prog-segment.learn {
    --state-color: var(--prog-relearn);
}

.prog-segment.new.done {
    order: -2;
}
.prog-segment.learn.done {
    order: -1;
}

.prog-segment.todo {
    order: 1;
}
.prog-segment.review.todo {
    order: 2;
}

3A. States (grouped)

Introduces additional category and respecitve supplementary color (gold) to display newly learned cards separately from relearned ones (which keep the default red Anki color). The ordering complies with Anki’s inner card “type” logic. Additionally shows future-due section and future (re)learning steps (in increasingly fainter colors):

Grouped states progress bar

Preset CSS
.prog-segment.prog-segment {
    order: 0;
    height: 7px;
}

.prog-segment.done {
    background: var(--state-color);
}

.prog-segment.todo {
    background: color-mix(in lab, var(--state-color) 30%, var(--canvas-elevated));
}

.prog-segment.cooldown {
    opacity: 0.4;
} 

3.5. Combined (ratings + states)

A setup combining ratings (for completed section of the bar) with card states (for the due section):

Combined ratings-states progress bar

Preset CSS
#lt-progress-bar {
    top: .25rem;
    width: 90vw;
    left: 5vw;
    border-radius: 5px;
    overflow: hidden;
}

.prog-segment.prog-segment {
    order: 0;
    height: 1rem;
}

.prog-segment.done {
    background: var(--rate-color);
}

.prog-segment.todo {
    background: color-mix(in lab, var(--state-color) 40%, var(--canvas-elevated));
}

.prog-segment.cooldown,
.prog-segment.future {
    display: none;
}

.prog-segment.again {
    order: -4;
}
.prog-segment.hard {
    order: -3;
}
.prog-segment.good {
    order: -2;
}
.prog-segment.easy {
    order: -1;
}

4. Multi-track states

A setup similar to #3, but with different states laid out into separate rows:

Multi-row states progress bar

Preset CSS
#lt-progress-bar span {
    flex-basis: 101%;
}

.prog-segment.prog-segment {
    order: 0;
}

.prog-segment:not(.empty) {
    min-width: 1px;
}

.prog-segment.done {
    background: var(--state-color);
}

.prog-segment.todo {
    background: color-mix(in lab, var(--state-color) 30%, var(--canvas-elevated));
}

.prog-segment.future,
.prog-segment.cooldown {
    display: none;
}

.prog-segment.learn {
    --state-color: var(--prog-relearn);
}

.prog-segment.learn.done {
    order: 1;
}
.prog-segment.learn.todo {
    order: 2;
}
.prog-segment.review + span {
    order: 3;
}
.prog-segment.review {
    order: 4;
}

#lt-progress-bar:not(:has(.prog-segment.new:not(.empty))) .prog-segment.new,
#lt-progress-bar:not(:has(.prog-segment.learn:not(.empty):not(.cooldown):not(.future))) .prog-segment.learn,
#lt-progress-bar:not(:has(.prog-segment.review:not(.empty))) .prog-segment.review {
    height: 0;
}

.prog-segment.animated {
    transition-property: flex-grow, height;
}

4A. Multi-track states (+learning)

Multi-track version of #3A, adds optional gaps between the progress segments:

Multi-row states progress bar with a separate learning section

Preset CSS
#lt-progress-bar span {
    flex-basis: 101%;
}

.prog-segment.prog-segment {
    order: 0;
}

.prog-segment.done {
    background: var(--state-color);
}

.prog-segment.todo {
    background: color-mix(in lab, var(--state-color) 30%, var(--canvas-elevated));
}

.prog-segment.cooldown {
    opacity: 0.4;
}

.prog-segment.new:not(.empty):is(.prog-segment.new:not(.empty) ~ .prog-segment),
.prog-segment.learn:not(.re):not(.empty):is(.prog-segment.learn:not(.re):not(.empty) ~ .prog-segment),
.prog-segment.review:not(.empty):is(.prog-segment.review:not(.empty) ~ .prog-segment),
.prog-segment.re.learn:not(.empty):is(.prog-segment.re.learn:not(.empty) ~ .prog-segment) {
    margin-left: 1px;
}

.prog-segment.new:has(.prog-segment.learn:not(.re):not(.empty)),
.prog-segment.learn:not(.re):has(.prog-segment.review:not(.empty)),
.prog-segment.review:has(.prog-segment.re.learn:not(.empty)) {
    margin-bottom: 1px;
}

#lt-progress-bar:not(:has(.prog-segment.new:not(.empty))) .prog-segment.new,
#lt-progress-bar:not(:has(.prog-segment.learn:not(.re):not(.empty))) .prog-segment.learn:not(.re),
#lt-progress-bar:not(:has(.prog-segment.review:not(.empty))) .prog-segment.review,
#lt-progress-bar:not(:has(.prog-segment.re.learn:not(.empty))) .prog-segment.re.learn {
    height: 0;
}

.prog-segment.animated {
    transition-property: flex-grow, height;
}

4B. Two-track states

Groups new cards with newly learned (both correspond to the “Learn” state in Anki’s “Card Info” logic), as well as review cards with relearned:

Two-row states progress bar

Preset CSS
#lt-progress-bar:has(:is(.new, .learn:not(.re)):not(.empty)):has(:is(.review,.re.learn):not(.empty)) {
    gap: 1px 0px;
}

#lt-progress-bar span:is(.new + span) {
    flex-basis: 101%;
}

.prog-segment.prog-segment {
    order: 0;
    height: 8px;
}

.prog-segment.done {
    background: var(--state-color);
}

.prog-segment.todo {
    background: color-mix(in lab, var(--state-color) 30%, var(--canvas-elevated));
}

.prog-segment.new.done {
    order: -4;
}
.prog-segment.learn.done {
    order: -3;
}
.prog-segment.new.todo {
    order: -2;
}
.prog-segment.learn.todo {
    order: -1;
}

.prog-segment.review.done {
    order: 1;
}
.prog-segment.re.done {
    order: 2;
}
.prog-segment.review.todo {
    order: 3;
}
.prog-segment.re.todo {
    order: 4;
}

.prog-segment.cooldown {
    opacity: 0.4;
}

.prog-segment.future {
    display: none;
}

#lt-progress-bar:not(:has(.prog-segment:is(.new, .learn:not(.re)):not(.empty))) .prog-segment:is(.new, .learn:not(.re)),
#lt-progress-bar:not(:has(.prog-segment:is(.review,.re.learn):not(.empty))) .prog-segment:is(.review,.re.learn) {
    height: 0;
}

5. Comprehensive

Provides the most detailed progress overview, displaying all combinations of card states, ratings, and readiness as individual segments:

Comprehensive progress bar

Preset CSS
#lt-progress-bar {
    top: .25rem;
    width: 90vw;
    left: 5vw;
    border-radius: 5px;
    overflow: hidden;
}

#lt-progress-bar span {
    flex-basis: 101%;
}

.prog-segment.prog-segment {
    order: 0;
}

.prog-segment:not(.empty) {
    min-width: 1px;
}

.prog-segment.done {
    background: color-mix(in lab, var(--rate-color) 80%, var(--state-color));
}

.prog-segment.todo {
    background: linear-gradient(to right, color-mix(in lab, var(--state-color) 60%, var(--canvas-elevated)), var(--state-color));
}

.prog-segment.cooldown {
    opacity: 0.6;
}

#lt-progress-bar:not(:has(.prog-segment.new:not(.empty))) .prog-segment.new {
    height: 0;
}
#lt-progress-bar:not(:has(.prog-segment.learn:not(.re):not(.empty))) .prog-segment.learn:not(.re) {
    height: 0;
}
#lt-progress-bar:not(:has(.prog-segment.review:not(.empty))) .prog-segment.review {
    height: 0;
}
#lt-progress-bar:not(:has(.prog-segment.re.learn:not(.empty))) .prog-segment.re.learn {
    height: 0;
}

.prog-segment.animated {
    transition-property: flex-grow, height;
}

5A. Comprehensive (smooth)

Alters the previous setup smoothing the transitions between individual segments and sacrificing some technical precision of the graph for a bit of aesthetic quality:

Smooth comprehensive progress bar

Preset CSS
#lt-progress-bar span {
    flex-basis: 101%;
}

.prog-segment.prog-segment {
    order: 0;
}

.prog-segment:not(.empty) {
    min-width: 1px;
}

.prog-segment.future,
.prog-segment.cooldown {
    opacity: 1;
}

.prog-segment.again {
    background: linear-gradient(to right, var(--stat-again), var(--stat-hard));
}
.prog-segment.hard {
    background: linear-gradient(to right, var(--stat-hard), var(--stat-good));
}
.prog-segment.good {
    background: linear-gradient(to right, var(--stat-good), var(--stat-easy));
}
.prog-segment.easy {
    background: linear-gradient(to right, var(--stat-easy), var(--prog-done));
}

.prog-segment.todo {
    background: linear-gradient(to right, var(--state-color), color-mix(in lab, var(--state-color) 60%, transparent));
}
.prog-segment.cooldown {
    background: linear-gradient(to right, color-mix(in lab, var(--state-color) 60%, transparent), color-mix(in lab, var(--state-color) 40%, transparent));
}
.prog-segment.future {
    background: linear-gradient(to right, color-mix(in lab, var(--state-color) 40%, transparent), color-mix(in lab, var(--state-color) 10%, transparent));
}

#lt-progress-bar:not(:has(.prog-segment.new:not(.empty))) .prog-segment.new {
    height: 0;
}
#lt-progress-bar:not(:has(.prog-segment.learn:not(.re):not(.empty))) .prog-segment.learn:not(.re) {
    height: 0;
}
#lt-progress-bar:not(:has(.prog-segment.review:not(.empty))) .prog-segment.review {
    height: 0;
}
#lt-progress-bar:not(:has(.prog-segment.re.learn:not(.empty))) .prog-segment.re.learn {
    height: 0;
}

.prog-segment.animated {
    transition-property: flex-grow, height;
}

How to set up

  1. Install the add-on (ToolsAdd-onsGet Add-ons... → paste “174803219” (the add-on id) → Ok → restart Anki)
  2. Open the add-on folder (ToolsAdd-ons → select “Anki Progression” → View Files)
  3. Open the “user_files” folder
  4. Edit the “common_styles.css” file in any text editor and copy-paste the desired preset CSS inside
  5. (optional) adjust the colors or any other parameters in the text
  6. Save and refresh Anki window (full restart is not required; if refreshing didn’t work, simply repeating it a few times should suffice for the changes to take effect)

Any of the “home_styles.css”, “deck_styles.css”, or “reviewer_styles.css” can be modified instead of the “common_styles.css” to selectively change the appearance of the progress bar in the respective Anki windows. Alternatively, the presets can be pasted into the styling tab of a card template to only apply the chosen setup when the respective cards are being reviewed in Anki.

General customization instructions


Classes

Progress bar segments are marked by .done and .todo classes for the completed reviews and sections counting the cards that are yet to be studied. Completed segments are then further marked by .again, .hard, .good, and .easy to distinguish between the different ratings assigned during the review.
Similarly .cooldown mark .todo segments counting reviews that will become available further in the day (cards already been reviewed and now are waiting for their next (re)learning step) and .future marks segments counting all future intraday (re)learning steps specified in deck settings that will come after the step a card is currently on. .todo without the two additional classes marks cards that are ready to be studied right now.
The state of cards counted by each segment are indicated by the .new, .learn, and .review classes. To further distinguish between learned and relearned cards, the later ones have additional .re class.

Full HTML source code
  <div id="lt-progress-bar">
      <div class="prog-segment new done again"></div>
      <div class="prog-segment new done hard"></div>
      <div class="prog-segment new done good"></div>
      <div class="prog-segment new done easy"></div>
      <div class="prog-segment new todo"></div>
      <span></span>
      <div class="prog-segment learn done again"></div>
      <div class="prog-segment learn done hard"></div>
      <div class="prog-segment learn done good"></div>
      <div class="prog-segment learn done easy"></div>
      <div class="prog-segment learn todo"></div>
      <div class="prog-segment learn todo cooldown"></div>
      <div class="prog-segment learn todo future"></div>
      <span></span>
      <div class="prog-segment review done again"></div>
      <div class="prog-segment review done hard"></div>
      <div class="prog-segment review done good"></div>
      <div class="prog-segment review done easy"></div>
      <div class="prog-segment review todo"></div>
      <span></span>
      <div class="prog-segment re learn done again"></div>
      <div class="prog-segment re learn done hard"></div>
      <div class="prog-segment re learn done good"></div>
      <div class="prog-segment re learn done easy"></div>
      <div class="prog-segment re learn todo"></div>
      <div class="prog-segment re learn todo cooldown"></div>
      <div class="prog-segment re learn todo future"></div>
  </div>

Segment colors

Colors are controlled via background property. To target specific progress segments or groups of segments the classes described above can be appended to the general .prog-segment class. For example, to change the color of all learned card reviews completed today, the following declaration should added to the styles:

.prog-segment.done.learn {
    background: RebeccaPurple;
}

(this will change the color for both learned and relearned cards, regardless of the rating they received during the study)
The colors can be specified using names from this list, or by copy-pasting their HEX code from a color-picker.

Setting the same color to multiple adjacent sections effectively merges them together and make them act as one.

Disabling segments

To remove certain components of the bar, display: none can be applied to them. For example:

.prog-segment.again {
    display: none;
}

removes reviews grades Again from the daily progress for all card states, while

.prog-segment.re.learn.future {
    display: none;
}

specifically disables display of the future relearning steps.

Reordering segments

The progress bar uses flexbox and its associated properties to control the layout. The order property can be employed to move the segments around. Elements with lesser values are located to the left of the elements with higher values, elements with the same order value are sorted according to their order in the source HTML code (see above). For example, to move new cards after all the other segments, the following declaration should be added:

.prog-segment.new {
    order: 2;
}

Note that some elements have order: 1 and order: -1 in the default progress bar style. All order values can be reset with the following declaration:

.prog-segment.prog-segment { /* double selector for increased specificity */
    order: 0;

(the reset should be placed before all assignments of the customized order values to avoid resetting them as well)

Grouping segments

For breaking the layout into multiple rows, the progress bar includes several <span> elements, which can be activated by adding

#lt-progress-bar span {
    flex-basis: 100%;
}

To target individual breaks, the selector should be changed to #lt-progress-bar span:nth-of-type(1) with the digit indicating the number of the <span> in the source code (see above).

The location of the line breaks can be controlled with the same order property described above.

Weights

On top of the ability to turn certain segments off and on completely (see above), the weights of the enabled sections can be changed in a continuous fashion. For example, adding the following declaration will make the reviews rated Again to contribute to the daily progress only half as much as everything else:

.prog-segment.again {
    flex-grow: calc(0.5 * var(--count));
}

Position

Position of the bar can be controlled directly through the constituents inset properties. Declaration for moving the bar to the bottom of the page, for example:

#lt-progress-bar {
    bottom: 0;
}

By default, the progress bar appears in the fixed place. Declaration for embedding it inside the overall layout and making it scrollable with the rest of the page:

#lt-progress-bar {
    position: static;
}

Width

By default, the width of the bar is set in viewport units to avoid it being compressed when a vertical scrollbar appears on the page. To change the width of the bar while keeping the centering, the following two rules can be added:

#lt-progress-bar {
    width: 80vw;
    left: 10vw; /* = (100 - 80) / 2 */
}

To set the width in the absolute units instead:

#lt-progress-bar {
    width: 420px;
    margin: 0 auto;
    right: 0;
}

(with absolute width the compression by the scrollbar is not an issue, so the centering can be automated)

Height

Because the height of the bar depends on the number of rows in the layout, it is better controlled via heights of individual segments instead of the bar as a whole:

.prog-segment {
    height: 15px;
}

Decorations

Some additional useful styles, such as rounding the borders and dropping a shadow:

#lt-progress-bar {
    border-radius: 4px;
    overflow: hidden;
    
    drop-shadow: 1px 1px 2px #0005;
}

Decorated presets

Some more styles for the progress bar with additional effects and animations

6. Relief

A variation on the #2 with simple frame and a sunken background:

Preset CSS
#lt-progress-bar {
    position: static;
    width: 500px;
    margin: 1rem auto;
    border-radius: 7px;
    overflow: hidden;
    padding: 5px;
    box-shadow: inset 0 1px 2px #0004, 0 1px #fff2;
    background: color-mix(in lab, var(--border-subtle) 50%, var(--canvas-elevated));
}

.prog-segment.prog-segment {
    order: 0;
    height: 20px;
}

.prog-segment.done {
    background: var(--rate-color);
}

.prog-segment.again:not(.empty):not(.prog-segment.again:not(.empty) ~ .prog-segment),
#lt-progress-bar:not(:has(.prog-segment.again:not(.empty))) .prog-segment.hard:not(.empty):not(.prog-segment.hard:not(.empty) ~ .prog-segment),
#lt-progress-bar:not(:has(.prog-segment:is(.again,.hard):not(.empty))) .prog-segment.good:not(.empty):not(.prog-segment.good:not(.empty) ~ .prog-segment),
#lt-progress-bar:not(:has(.prog-segment:is(.again,.hard,.good):not(.empty))) .prog-segment.easy:not(.empty):not(.prog-segment.easy:not(.empty) ~ .prog-segment) {
    border-top-left-radius: 5px;
    border-bottom-left-radius: 5px;
}

.prog-segment.easy:not(.empty):not(:has(~ .prog-segment.easy:not(.empty))),
#lt-progress-bar:not(:has(.prog-segment.easy:not(.empty))) .prog-segment.good:not(.empty):not(:has(~ .prog-segment.good:not(.empty))),
#lt-progress-bar:not(:has(.prog-segment:is(.easy,.good):not(.empty))) .prog-segment.hard:not(.empty):not(:has(~ .prog-segment.hard:not(.empty))),
#lt-progress-bar:not(:has(.prog-segment:is(.easy,.good,.hard):not(.empty))) .prog-segment.again:not(.empty):not(:has(~ .prog-segment.again:not(.empty))) {
    border-top-right-radius: 5px;
    border-bottom-right-radius: 5px;
}

.prog-segment.todo {
    background: var(--border-subtle);
    opacity: 0;
}

.prog-segment.cooldown,
.prog-segment.future {
    display: none;
}

.prog-segment.again {
    order: -4;
}
.prog-segment.hard {
    order: -3;
}
.prog-segment.good {
    order: -2;
}
.prog-segment.easy {
    order: -1;
}

7. Glow

Displays stats similar to #3, but with a distinct “Learned” section and without coloring future reviews:

Preset CSS (Animated)
#lt-progress-bar {
    position: relative;
    width: 500px;
    margin: 1rem auto;
    border-radius: 20px;
    padding: 4px;
    box-shadow: 0 0 20px 4px #0005,
                inset 0 0 10px 2px #0002;
    background: color-mix(in lab, #202020 50%, var(--border-subtle));
}

#lt-progress-bar::before,
#lt-progress-bar::after {
    position: absolute;
    content: '';
}

#lt-progress-bar::before {
    inset: 0;
    background: linear-gradient( to bottom, white, transparent 40%, transparent 60%, white);
    margin: 2px;
    opacity: 0.2;
    border-radius: 20px;
}

#lt-progress-bar::after {
    top: 30%;
    height: 60%;
    background: linear-gradient( to bottom, white, white 10%, transparent 50%);
    left: 2%;
    right: 10%;
    opacity: 0.4;
    border-radius: 10px/20px;
    mask-image: linear-gradient(to right, black 60%, transparent 100%);
    mask-repeat: no-repeat;
    mask-size: 100% 100%;
}

.prog-segment.prog-segment {
    order: 0;
    height: 8px;
    position: relative;
}

.prog-segment.done {
    background: var(--state-color);
    box-shadow: 0 0 7px var(--state-color);
}

@keyframes flicker {
  from {
    box-shadow: 0 0 2px var(--glow-color),
                0 0 8px var(--state-color),
                0 0 18px color-mix(in lab, var(--state-color) 60%, darkblue);
  }
  to {
    box-shadow: 0 0 4px 1px var(--glow-color),
                0 0 12px 2px color-mix(in lab, var(--state-color) 25%, var(--glow-color)),
                0 0 20px 2px color-mix(in lab, var(--state-color) 60%, darkblue);
  }
}

.prog-segment.done:not(.empty)::before {
    content: '';
    position: absolute;
    inset: 0;
    display: block;
    animation: flicker 4s ease-in-out infinite alternate;
    z-index: -1;
}
.prog-segment.learn::before {
    animation-duration: 3.812s;
}
.prog-segment.re.learn::before {
    animation-duration: 3.1415s;
}
.prog-segment.new::before {
    animation-duration: 4.2423s;
}

.prog-segment:not(.empty):not(.prog-segment:not(.empty) ~ .prog-segment)::before,
.prog-segment:not(.empty):not(.prog-segment:not(.empty) ~ .prog-segment) {
    border-radius: 10px 0 0 10px;
}
.prog-segment.done:not(.empty):not(:has(~ .prog-segment.done:not(.empty)))::before,
.prog-segment.done:not(.empty):not(:has(~ .prog-segment.done:not(.empty))) {
    border-radius: 0 10px 10px 0;
}

.prog-segment.todo {
    background: var(--border-subtle);
    opacity: 0;
}

.prog-segment.future {
    display: none;
}

.prog-segment.done {
    order: -2;
}

.prog-segment.new {
    --state-color: color-mix(in lab, var(--prog-new) 50%, #3b82f6);
    --glow-color: var(--prog-new);
}
.prog-segment.learn {
    --glow-color: yellow;
}
.prog-segment.re.learn {
    --state-color: color-mix(in lab, var(--prog-relearn) 50%, #dc2626);
    --glow-color: var(--prog-relearn);
}
.prog-segment.review {
    --state-color: color-mix(in lab, var(--prog-review) 50%, #16a34a);
    --glow-color: var(--prog-review);
}

The smooth animations only supported in the latest Anki (26.05). For earlier versions (or to simply get rid of the redundant motion) a non-animated style is recommended:

Preset CSS
#lt-progress-bar {
    position: relative;
    width: 500px;
    margin: 1rem auto;
    border-radius: 20px;
    padding: 4px;
    box-shadow: 0 0 20px 4px #0005,
                inset 0 0 10px 2px #0002;
    background: color-mix(in lab, #202020 50%, var(--border-subtle));
}

#lt-progress-bar::before,
#lt-progress-bar::after {
    position: absolute;
    content: '';
}

#lt-progress-bar::before {
    inset: 0;
    background: linear-gradient( to bottom, white, transparent 40%, transparent 60%, white);
    margin: 2px;
    opacity: 0.2;
    border-radius: 20px;
}

#lt-progress-bar::after {
    top: 30%;
    height: 60%;
    background: linear-gradient( to bottom, white, white 10%, transparent 50%);
    left: 2%;
    right: 10%;
    opacity: 0.4;
    border-radius: 10px/20px;
    mask-image: linear-gradient(to right, black 60%, transparent 100%);
    mask-repeat: no-repeat;
    mask-size: 100% 100%;
}

.prog-segment.prog-segment {
    order: 0;
    height: 8px;
    position: relative;
}

.prog-segment.done {
    background: var(--state-color);
    box-shadow: 0 0 7px var(--state-color);
}

.prog-segment.done:not(.empty)::before {
    content: '';
    position: absolute;
    inset: 0;
    display: block;
    box-shadow: 0 0 4px var(--glow-color),
                0 0 10px 1px var(--state-color),
                0 0 19px 1px color-mix(in lab, var(--state-color) 60%, darkblue);
    z-index: -1;
}
.prog-segment.learn::before {
    animation-duration: 3.812s;
}
.prog-segment.re.learn::before {
    animation-duration: 3.1415s;
}
.prog-segment.new::before {
    animation-duration: 4.2423s;
}

.prog-segment:not(.empty):not(.prog-segment:not(.empty) ~ .prog-segment)::before,
.prog-segment:not(.empty):not(.prog-segment:not(.empty) ~ .prog-segment) {
    border-radius: 10px 0 0 10px;
}
.prog-segment.done:not(.empty):not(:has(~ .prog-segment.done:not(.empty)))::before,
.prog-segment.done:not(.empty):not(:has(~ .prog-segment.done:not(.empty))) {
    border-radius: 0 10px 10px 0;
}

.prog-segment.todo {
    background: var(--border-subtle);
    opacity: 0;
}

.prog-segment.future {
    display: none;
}

.prog-segment.done {
    order: -2;
}

.prog-segment.new {
    --state-color: color-mix(in lab, var(--prog-new) 50%, #3b82f6);
    --glow-color: var(--prog-new);
}
.prog-segment.learn {
    --glow-color: yellow;
}
.prog-segment.re.learn {
    --state-color: color-mix(in lab, var(--prog-relearn) 50%, #dc2626);
    --glow-color: var(--prog-relearn);
}
.prog-segment.review {
    --state-color: color-mix(in lab, var(--prog-review) 50%, #16a34a);
    --glow-color: var(--prog-review);
}

8. Anki particles

Animation (has extra effect on reaching full completion):

Progress animation

A simple progress bar distinguishing only between completed reviews and due cards similar to #1:

Preset CSS (Animated)
#lt-progress-bar {
    position: relative;
    width: 500px;
    margin: 1rem auto;
    border-radius: 20px;

    overflow: hidden;
    box-shadow: 0 0 20px 4px #0005,
                inset 0 0 10px 2px #0002;
    background: color-mix(in lab, #202020 50%, var(--border-subtle));
}

#lt-progress-bar::before,
#lt-progress-bar::after {
    position: absolute;
    content: '';
}

#lt-progress-bar::before {
    inset: 0;
    background: linear-gradient( to bottom, white, transparent 40%, transparent 60%, white);
    margin-bottom: 2px;
    opacity: 0.1;
    border-radius: 20px;
}

#lt-progress-bar::after {
    top: 20%;
    height: 60%;
    background: linear-gradient( to bottom, white, white 10%, transparent 50%);
    left: 2%;
    right: 10%;
    opacity: 0.2;
    border-radius: 10px/20px;
    mask-image: linear-gradient(to right, black 60%, transparent 100%);
    mask-repeat: no-repeat;
    mask-size: 100% 100%;
}


.prog-segment.prog-segment {
    order: 0;
    height: 24px;
}

.prog-segment.done {
    background: linear-gradient(to bottom, var(--button-primary-bg), royalblue 50%, var(--button-primary-disabled));
}

.prog-segment:not(.empty):not(.prog-segment:not(.empty) ~ .prog-segment) {
    border-radius: 10px 0 0 10px;
}

.prog-segment.done:not(.empty):not(:has(~ .prog-segment.done:not(.empty))) {
    border-radius: 0 5px 5px 0;
    position: relative;
}
.prog-segment.done:not(.empty):not(:has(~ .prog-segment.done:not(.empty)))::before,
.prog-segment.done:not(.empty):not(:has(~ .prog-segment.done:not(.empty)))::after {
    border-radius: 0 5px 5px 0;
    content: '';
    display: block;
    height: 100%;
    right: 0;
    position: absolute;
    width: 50px;
}

.prog-segment.done:not(.empty):not(:has(~ .prog-segment.done:not(.empty)))::after {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-100 0 200 100'><style>use{transform-box:fill-box;transform-origin: center;animation: particle var(--dur) infinite linear;animation-delay: calc(-15.6512 * var(--dur))} @keyframes particle {from {opacity: 0; rotate: calc(1*var(--rot));scale: calc(var(--scale,1)*50%25);translate:50%25 var(--y);} 10%25{opacity: 0.65} to {rotate: calc(2*var(--rot));translate: calc(-1 * var(--dist)) var(--y);scale: 0%;opacity: .25}}</style><defs><path id='ankistar' d='M55.077,11.428l6.308,15.857c1.463,4.503,5.66,7.552,10.395,7.552l17.03,1.1c5.171,0,7.321,6.617,3.138,9.657l-13.131,10.899c-3.831,2.783-5.434,7.717-3.97,12.22l4.217,16.536c1.598,4.918-4.031,9.008-8.214,5.968l-14.424-9.12c-3.831-2.783-9.018-2.783-12.849,0l-14.424,9.12c-4.183,3.039-9.812-1.05-8.214-5.968l4.217-16.536c1.463-4.503-.14-9.437-3.97-12.22l-13.131-10.899c-4.183-3.039-2.033-9.657,3.138-9.657l17.03-1.1c4.735,0,8.932-3.049,10.395-7.552l6.308-15.857c1.598-4.918,8.556-4.918,10.154,0Z' stroke='%23aef' fill='none' stroke-width='10' /></defs><use href='%23ankistar' style='--dur: 1s; --dist: 140px; --y: 50px; --rot: 100deg; --scale: 1.5;'></use><use href='%23ankistar' style='--dur: 1.414s; --dist: 210px; --y: -20px; --rot: -150deg'></use><use href='%23ankistar' style='--dur: 1.134s; --dist: 190px; --y: -40px; --rot: -120deg; --scale: 1.25;'></use><use href='%23ankistar' style='--dur: 0.791s; --dist: 170px; --y: 30px; --rot: -90deg'></use><use href='%23ankistar' style='--dur: 1.319s; --dist: 190px; --y: 5px; --rot: 125deg; --scale: 0.95;'></use><use href='%23ankistar' style='--dur: 0.819s; --dist: 160px; --y: -15px; --rot: -222deg'></use><use href='%23ankistar' style='--dur: 0.914s; --dist: 195px; --y: 65px; --rot: 302deg'></use><use href='%23ankistar' style='--dur: 1.314s; --dist: 175px; --y: 35px; --rot: 122deg; --scale: 1.75;'></use></svg>");
    background-repeat: no-repeat;
    background-size: contain;
    background-position: right center;
    opacity: 1;

}
@keyframes outerGlow {
  from {
    box-shadow:  0 0 3px 2px white,
                 0 0 5px 5px cyan,
                 0 0 12px 12px royalblue,
                 0 0 18px 20px darkblue;
  }
  to {
    box-shadow:  0 0 2px 2px #def,
                 0 0 4px 5px cyan,
                 0 0 8px 11px royalblue,
                 0 0 14px 17px darkblue;
  }
}
@keyframes innerGlow {
  from {
    opacity: 1;
  }
  to {
    opacity: .9;
  }
}
.prog-segment.done:not(.empty):not(:has(~ .prog-segment.done:not(.empty)))::before {
    background: linear-gradient(to left, #fffc, #4dfa 12px, transparent 25px);
    filter: blur(1px);
    width: 100vw;
    animation: outerGlow 4s infinite alternate ease-in-out,
               innerGlow 1.15s infinite alternate ease-in-out;
}

#lt-progress-bar:not(:has(.todo:not(.empty))) {
    filter: hue-rotate(-80deg);
    transition: filter .5s ease;
}

.prog-segment.todo {
    background: var(--border-subtle);
    opacity: 0;
}

.prog-segment.cooldown,
.prog-segment.future {
    display: none;
}

.prog-segment.done {
    order: -2;

Setup instructions for all presets