Patterns

Inline links inside flowing text are styled through the .prose class on the container element. This approach scopes the link style to reading contexts only; card layouts, nav elements, and list templates are deliberately excluded.

Visual appearance:

The SAMM model provides five business functions that organize security practices. Each function contains three security practices, each with two streams of activity at increasing maturity levels.
StateColourUnderline
Default--color-mid (#366867)Teal tint, 1.5px, offset 0.15em
Hover--color-primary (#71b8b8)Solid, 2px
Mobile--color-midAlways underlined (reinforced via responsive.css)

The rule in docs.css:

.prose a:not(.btn):not(.agenda-program__link) { ... }
.prose a:not(.btn):not(.agenda-program__link):hover { ... }

Where .prose is applied

Add .prose only to containers that render flowing markdown. Card and list templates omit it intentionally; their <a> elements are structural, not inline text links.

TemplateElement
layouts/docs/single.html<article class="docs__body content prose">
layouts/blog/single.html<article class="content prose">
layouts/_default/single.html<article class="content prose">
layouts/contact/single.html<article class="content prose">
layouts/user-day/single.html<article class="content prose">
layouts/stream/single.html<article class="content stream-content prose">
layouts/samm-identity/single.html<article class="docs__body content prose">
layouts/internal/single.html<article class="docs__body content prose">
layouts/practice/single.html<div class="practice-description prose"> — scoped to description only

Do not add .prose to: docs/list.html, business-function/single.html, or any template whose <article> contains card-style <a> elements.

Why not .content a? The old pattern used .content a:not(… 8 exclusions …). Every new card component required a new exclusion. The .prose approach inverts the logic: opt in at the container level rather than opt out per component. Adding a new card layout inside a prose container is now the exceptional case, handled by adding to the :not() list.

Adding a new exclusion

If a new card-style link appears inside a .prose container and picks up unwanted underlines, add it to both the base rule and the :hover variant in docs.css:

.prose a:not(.btn):not(.agenda-program__link):not(.your-new-class) { ... }
.prose a:not(.btn):not(.agenda-program__link):not(.your-new-class):hover { ... }

Links on model pages inherit their color from the business function context rather than from .prose.

How it works:

  1. A wrapper element has --bf-color and --bf-color-light set (via a .model-bf--* or .skills-bf-group--* class).
  2. Links inside inherit: color: var(--bf-color).
  3. Hover shifts to: color: var(--bf-color-light).

Override rules use deep descendant selectors (specificity 0-7-2+) to win over .prose a without !important or hacks:

/* Practice stream heading links — high specificity to beat .prose a */
.docs .docs__content .docs__body.content .practice-content
  .practice-streams .practice-stream h3 a { ... }
Never fight with !important. When a BF-coloured link needs to override the prose rule, increase specificity by adding more ancestor selectors that already exist in the DOM. This makes the override traceable and reversible. A comment in the CSS should explain which component triggered the override.

Links in navigational contexts — header, footer, sidebar, pager — follow different rules than prose links.

ContextUnderlineColourNotes
Header navNoneOffwhite / mid-teal on hoverNav links are self-evidently interactive
FooterNoneMuted; mid-teal on hoverNavigation context sufficient
Docs sidebarNone (is-active: bold + teal)--color-text-light; primary on hoverActive state uses font-weight + color
Pager cardsNoneDark; teal on hoverCard border + chevron = affordance
Practice stream h3 aNone on desktop; underline on mobileBF colorMobile rule in responsive.css for tap affordance

Mobile underline rule for stream h3:

@media (max-width: 48rem) {
  .docs.model-docs .docs__content .content.practice-content
    .practice-streams .practice-stream h3 a {
    text-decoration: underline;
    text-decoration-color: currentColor;
    text-underline-offset: 0.15em;
  }
}

This is a mobile-only override; desktop stream headings rely on their BF color and position as headings to signal interactivity. Mobile adds underlines because hover states don’t exist and the heading color alone may not be sufficient affordance on a small screen.