/*
 * Component anatomy — feature 017, ADR-0001.
 *
 * UNSCOPED ON PURPOSE, exactly like `_layout.css` beside it, and for a related reason.
 * `_layout.css` owns arrangement because arrangement does not differ per theme. This file
 * owns *anatomy* — which element is a surface, which carries a border, which sits on the
 * inverse ground — because that does not differ per theme either. What differs is the
 * VALUES, and those are the token block each theme file declares.
 *
 * Before this file existed, each theme restated every component with its own literals. The
 * result was not merely duplication: `.cms-page-header` was painted under `minimal` and
 * `funky` and not under `default`, and `.cms-footer-cta` the same, so a client picking the
 * default theme got unstyled bands and nothing failed. A component described once cannot
 * drift that way, and `ThemeTokenContractTest` asserts the token sets stay identical.
 *
 * Named with a leading underscore so `UiTheme::available()` does not offer it as a theme —
 * see that class. Custom-property resolution does not depend on file order, so the sort
 * position of this file relative to the themes is cosmetic.
 *
 * ---------------------------------------------------------------------------
 * THE 4px SPACING SCALE IS WRITTEN AS LITERALS HERE, NOT AS TOKENS.
 *
 * s1…s9 are 4 · 8 · 12 · 16 · 24 · 32 · 48 · 64 · 96, and they are the same under every
 * theme — a scale is the design's vocabulary, not a knob a skin turns. What a skin does turn
 * is the *rhythm* built out of that scale, and those are tokens: `--seef-core-section-py`,
 * `--seef-core-block-gap`, `--seef-core-gutter`, `--seef-core-container`, `--seef-core-prose-max`.
 *
 * Declaring the scale as custom properties here would also break the contract this file is
 * held to: `ThemeTokenContractTest` requires every `--seef-core-*` this file READS to be declared
 * by every theme, and a scale declared here and read here would be declared by none of them.
 *
 * Design source: `design/cms-public-site-canvas/`, artboards 01 (tokens) and 02 (components).
 * ------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
 * Two things every component below assumes, stated rather than inherited
 *
 * BORDER-BOX. Tailwind's preflight sets it globally, and this stylesheet is served to pages
 * whose build may not include preflight at all — `vendor/` is normally git-ignored, which
 * Tailwind 4's source detection skips, so a consuming project's bundle is not something this
 * package may rely on. Under `content-box` a `.cms-btn` at `width: 100%` is the column plus
 * its two 1px borders, which is 362px in a 360px viewport: the document scrolls sideways
 * because of a border. Every component here therefore states its own box model.
 *
 * ICON SIZE. The same reasoning, for the same reason. Icons were sized with `w-5 h-5` in the
 * Blade views; where those utilities do not compile, an inline SVG with no intrinsic size
 * stretches to its container, and a chevron inside a flex row rendered 310px wide. A size
 * declared here needs no build anywhere.
 * ------------------------------------------------------------------------- */

.cms-btn,
.cms-card,
.cms-card-inner,
.cms-chip,
.cms-type-badge,
.cms-social,
.cms-partner-tile,
.cms-accordion,
.cms-accordion-trigger,
.cms-accordion-panel,
.cms-cta-pill,
.cms-icon-pill,
.cms-empty,
.cms-empty-icon,
.cms-input,
.cms-textarea,
.cms-select,
.cms-page-header,
.cms-widget-grid,
.cms-popover-panel,
.cms-dropdown {
    box-sizing: border-box;
}

.cms-btn svg,
.cms-card-action svg,
.cms-chip svg,
.cms-type-badge svg,
.cms-social svg,
.cms-icon-pill svg,
.cms-cta-pill svg,
.cms-contact-strip svg,
.cms-breadcrumb svg,
.cms-accordion-trigger svg,
.cms-chevron {
    flex: none;
    width: 1.25rem;
    height: 1.25rem;
}

.cms-breadcrumb svg,
.cms-cta-pill svg,
.cms-contact-strip svg,
.cms-field-error svg {
    flex: none;
    width: 1rem;
    height: 1rem;
}

.cms-icon-pill svg,
.cms-empty-icon svg {
    width: 1.5rem;
    height: 1.5rem;
}

/* ---------------------------------------------------------------------------
 * The page
 * ------------------------------------------------------------------------- */

body.cms-body {
    background-color: var(--seef-core-page-bg);
    color: var(--seef-core-text);
    font-family: var(--seef-core-font-body);
    font-size: var(--seef-core-body-size);
    line-height: var(--seef-core-body-leading);
    /*
     * Arabic is a joined script: tracking pulls the joins apart and is never negative here.
     * Stated on the body so a stray utility has something explicit to be overridden by.
     */
    letter-spacing: 0;
}

.cms-main {
    background-color: var(--seef-core-page-bg);
}

/*
 * One focus treatment for the whole site, including the pop-over close.
 *
 * It uses `--seef-core-primary-text` — the lightness-clamped primary — rather than the raw brand,
 * because the ring has to be visible against white at any hue a client might type. That is
 * the same reason the token exists at all; see `Seef\Core\Support\BrandTokens::primaryText()`.
 */
.cms-body :focus-visible {
    outline: var(--seef-core-focus-ring);
    outline-offset: var(--seef-core-focus-offset);
}

/* ---------------------------------------------------------------------------
 * The container
 *
 * Twenty-five places in this package's views lay content out with `container mx-auto`, and
 * Tailwind's `.container` supplies NO horizontal padding — it is `width: 100%` plus a set of
 * breakpoint max-widths. So every one of them ran to the edge of the screen, and at ≥1536px ran
 * to 96rem, when the design's measure is 1152 with gutters of 32 / 24 / 16.
 *
 * The `--seef-core-container` and `--seef-core-gutter*` tokens existed for this from the start and only
 * `.cms-widget-grid` ever read them. Stated here, every container on the public site gets the
 * drawn measure, and none of it depends on a consuming project's build.
 * ------------------------------------------------------------------------- */

.cms-body .container {
    /*
     * `box-sizing` first, and not as a formality. Under `content-box` a `width: 100%` element
     * with a 16px gutter is 392px wide in a 360px viewport, and the whole document scrolls
     * sideways — the browser suite caught exactly that the moment this rule was added. The
     * shared border-box list above cannot cover it: `.container` is Tailwind's class, not ours.
     */
    box-sizing: border-box;
    width: 100%;
    max-width: var(--seef-core-container);
    margin-inline: auto;
    padding-inline: var(--seef-core-gutter);
}

@media (max-width: 1279px) {
    .cms-body .container {
        padding-inline: var(--seef-core-gutter-tablet);
    }
}

@media (max-width: 767px) {
    .cms-body .container {
        padding-inline: var(--seef-core-gutter-phone);
    }
}

/* ---------------------------------------------------------------------------
 * Shell — header, the page-title band, footer
 * ------------------------------------------------------------------------- */

.cms-header {
    background-color: var(--seef-core-surface);
    border-bottom: var(--seef-core-header-border);
}

/*
 * The active navigation item is marked by an inset rule, not a fill: a fill would need an
 * on-colour computed for it, and the header is the one surface where the brand should not
 * shout. `box-shadow` rather than `border` so the item does not change height when it
 * becomes active.
 */
.cms-nav-item {
    color: var(--seef-core-text);
    padding: 8px 12px;
    transition: var(--seef-core-transition);
}

.cms-nav-item:hover {
    color: var(--seef-core-primary-text);
}

.cms-nav-item[aria-current],
.cms-nav-item.is-active {
    color: var(--seef-core-primary-text);
    box-shadow: inset 0 -2px 0 0 var(--seef-core-primary);
}

/*
 * No `display` here, deliberately.
 *
 * The shell renders this band as a `<span>` carrying Tailwind's `hidden` when the screen
 * supplies no breadcrumbs. This file is served UNLAYERED and Tailwind's utilities sit in a
 * layer, so an unlayered `display: block` here beats `.hidden` — which is the property
 * feature 008 established and which, stated the other way round, means a rule in this file
 * can silently switch a utility off. It did: every screen without breadcrumbs rendered an
 * empty 101px band. The band's own children are block-level, so nothing needs it.
 */
.cms-page-header {
    background-color: var(--seef-core-surface);
    border-bottom: var(--seef-core-hairline-width) solid var(--seef-core-line);
    padding-block: 48px;
}

.cms-page-header h1,
.cms-page-header .cms-page-title {
    font-family: var(--seef-core-font-display);
    font-size: var(--seef-core-h1-size);
    font-weight: var(--seef-core-h1-weight);
    line-height: var(--seef-core-h1-leading);
    color: var(--seef-core-text);
    margin: 0;
    /*
     * A long headline wraps to three lines and the band grows. Nothing clamps and nothing
     * truncates — a title the editor wrote is the one thing on the screen that must survive
     * intact. `pretty` keeps a one-word last line off the end.
     */
    text-wrap: pretty;
}

/*
 * Date, reading time and the category chips, beneath the title. It WRAPS — at 360 the meta
 * takes two rows and the chips get a row of their own — so nothing is squeezed and nothing
 * pushes the document sideways.
 */
.cms-page-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 16px;
    margin-top: 16px;
    font-size: var(--seef-core-small-size);
    color: var(--seef-core-text-muted);
}

/*
 * The breadcrumb wraps rather than truncating, which is what stops a long category name
 * pushing the document sideways. The separator is a glyph in markup, rotated by direction in
 * `_layout.css`; the current page is ink and is not a link.
 */
.cms-breadcrumb {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    font-size: var(--seef-core-small-size);
    color: var(--seef-core-text-muted);
}

.cms-breadcrumb a {
    color: var(--seef-core-text-muted);
    text-decoration: none;
}

.cms-breadcrumb a:hover {
    color: var(--seef-core-primary-text);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.cms-breadcrumb [aria-current='page'] {
    color: var(--seef-core-text);
}

.cms-footer {
    background-color: var(--seef-core-surface-footer) !important;
    color: var(--seef-core-text-on-inverse) !important;
}

.cms-footer a {
    color: var(--seef-core-text-on-inverse);
}

/*
 * The footer's columns, in CSS rather than as `md:grid-cols-3`.
 *
 * That utility appears ONLY in this package's footer, and a consuming project's Tailwind does
 * not scan `vendor/` — so it compiled to nothing and the footer stacked into a single column on
 * a client site while looking correct in the package's own tests. Measured on a live bundle:
 * `grid-cols-1` and `gap-8` were present because the project happens to use them elsewhere;
 * `md:grid-cols-3` was absent. This is feature 013's lesson arriving in the one part of the
 * shell that had not yet been moved.
 */
.cms-footer-columns {
    display: grid;
    grid-template-columns: 1fr;
    gap: 32px;
}

@media (min-width: 768px) {
    .cms-footer-columns {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

.cms-footer-links {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.cms-footer-heading {
    font-size: var(--seef-core-small-size);
    font-weight: 500;
    margin: 0 0 12px;
}

/* The credit row sits clear of the columns above it. */
/*
 * The rights line, with or without a credit beside it.
 *
 * Two class names for one row, because the kernel's shell renders `.cms-footer-credit` when
 * an install has configured a "developed and maintained by" credit and `.cms-footer-rights`
 * when it has not — and an install that has not is the commonest install there is. Before
 * feature 029 this package's shell rendered `.cms-footer-credit` either way, so the second
 * name has no rules of its own anywhere and the row lost its top margin on every site that
 * never configured a credit. Found by AC-39's comparison against the recorded 0.9.x
 * baseline: the footer came back 45px shorter on all twenty measured cells and nothing else
 * in the page had moved at all.
 */
.cms-footer-credit,
.cms-footer-rights {
    margin-top: 48px;
    font-size: var(--seef-core-small-size);
}

/*
 * The footer CTA and the ContactUs block are ONE component with two placements — the shell's
 * band and a block on the page. `--seef-core-cta-surface` is the editor's colour and falls back to
 * the theme's inverse surface; its ink is computed from whichever of those it resolves to, so
 * the band never carries muted ink and never carries an alpha.
 */
.cms-footer-cta,
.cms-contact-banner {
    background-color: var(--seef-core-cta-surface);
    color: var(--seef-core-text-on-cta);
}

.cms-footer-cta a,
.cms-contact-banner a {
    color: var(--seef-core-text-on-cta);
}

/*
 * The band's own padding. It is NOT `.cms-section`: that class paints a surface background,
 * which would cover the very colour this band exists to show.
 */
.cms-cta-inner,
.cms-footer {
    padding-block: var(--seef-core-section-py);
}

.cms-cta-title {
    margin: 16px 0 0;
    font-family: var(--seef-core-font-display);
    font-size: var(--seef-core-h2-size);
    font-weight: var(--seef-core-h2-weight);
    line-height: var(--seef-core-h2-leading);
}

/*
 * Full-strength ink, not `opacity: .5`. This band is the one surface whose colour the editor
 * chooses, so it is the last place a ratio should depend on what happens to be behind it.
 */
.cms-cta-description {
    margin: 8px auto 0;
    max-width: 68ch;
    font-size: var(--seef-core-body-size);
    color: var(--seef-core-text-on-cta);
}

/*
 * The pill on the inverse band. `currentColor` at 40% is a BORDER, not text — the one place an
 * alpha is legitimate, because nothing has to be read through it.
 */
.cms-cta-pill {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 4px 16px;
    border: 1px solid color-mix(in srgb, currentColor 40%, transparent);
    border-radius: var(--seef-core-radius-pill);
    font-size: var(--seef-core-small-size);
}

/*
 * The contact strip — one component for the footer CTA, the ContactUs card and the contact
 * page. It wraps rather than scrolling, so a long phone number and a long address do not push
 * the document sideways on a phone.
 */
.cms-contact-strip {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 8px 24px;
    margin-top: 32px;
    font-size: var(--seef-core-small-size);
}

.cms-contact-strip > span {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

/* ---------------------------------------------------------------------------
 * Hero and sections
 * ------------------------------------------------------------------------- */

.cms-hero {
    background-color: var(--seef-core-surface);
    padding-top: var(--seef-core-section-py);
    padding-bottom: var(--seef-core-section-py);
}

.cms-hero h1 {
    font-family: var(--seef-core-font-display);
    font-size: var(--seef-core-display-size);
    font-weight: var(--seef-core-h1-weight);
    line-height: var(--seef-core-h1-leading);
    color: var(--seef-core-text);
    text-wrap: pretty;
}

.cms-hero h4 {
    color: var(--seef-core-text-muted);
    font-size: var(--seef-core-body-size);
    font-weight: 400;
    /*
     * Was `opacity: .5`. Opacity on text cannot be measured for contrast — the ratio depends
     * on whatever happens to be behind it — so every muted run in this package is now an
     * opaque colour instead. `opacity: 1` is stated because the markup still carries the
     * utility in places.
     */
    opacity: 1;
}

/*
 * `.cms-section` IS RHYTHM, NOT A BAND.
 *
 * It carries the section's vertical spacing and nothing else. It deliberately does not paint a
 * background, because most of the elements wearing it sit INSIDE `.cms-widget-grid`'s gutters
 * — a background here would render as a white stripe inset from both edges of the page, which
 * is not a band, it is a box with no border.
 *
 * The design draws the landing page as full-bleed bands alternating `--seef-core-surface` and
 * `--seef-core-page-bg` with a hairline between. That needs the page-builder frame to be full width
 * with the gutters moved inside each block, which is a change to how blocks are composed
 * rather than to what a block looks like. It is not in this pass; see ADR-0002.
 */
.cms-section {
    padding-top: var(--seef-core-section-py);
    padding-bottom: var(--seef-core-section-py);
}

/* ---------------------------------------------------------------------------
 * Section header — eyebrow / title / description
 *
 * One component, inherited by every page-builder block. The eyebrow is Latin-only micro type
 * and is the sole place tracking is allowed; a block with nothing to say simply omits it, and
 * an omitted description reserves no space.
 * ------------------------------------------------------------------------- */

.cms-section-header {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 32px;
}

.cms-section-header .cms-eyebrow {
    font-family: var(--seef-core-font-mono);
    font-size: var(--seef-core-label-size);
    font-weight: var(--seef-core-label-weight);
    letter-spacing: var(--seef-core-label-tracking);
    color: var(--seef-core-primary-text);
}

.cms-section-header h2,
.cms-section-header .cms-section-title {
    margin: 0;
    font-family: var(--seef-core-font-display);
    font-size: var(--seef-core-h2-size);
    font-weight: var(--seef-core-h2-weight);
    line-height: var(--seef-core-h2-leading);
    color: var(--seef-core-text);
}

.cms-section-header p {
    margin: 0;
    max-width: 68ch;
    font-size: var(--seef-core-small-size);
    line-height: var(--seef-core-small-leading);
    color: var(--seef-core-text-muted);
}

/* The centred variant, used by the partners band and the closing CTA. */
.cms-section-header--center {
    align-items: center;
    text-align: center;
}

/* ---------------------------------------------------------------------------
 * Cards
 *
 * The 450px min-height is gone. Cards in a row align because their INNER ROWS align — media,
 * meta, title, excerpt, a `1fr` spacer, action — not because every card is floored to the
 * height of the tallest possible one. That floor is what made a card with two lines of text
 * mostly empty space, and it did not even work: a card with more content simply exceeded it.
 * ------------------------------------------------------------------------- */

.cms-card {
    background-color: var(--seef-core-surface);
    border: var(--seef-core-card-border);
    border-radius: var(--seef-core-radius-card);
    transition: var(--seef-core-transition);
    /* No shadow. Cards are separated from the page by the hairline, never by depth. */
    overflow: hidden;
}

/*
 * Hover moves the border and the title, and nothing else. No lift, no scale, no shadow —
 * a transform under the pointer is the one motion the design removes everywhere.
 */
.cms-card:hover {
    border-color: var(--seef-core-primary);
}

.cms-card:hover .cms-card-title {
    color: var(--seef-core-primary-text);
}

/*
 * Media / meta / title / excerpt, then a `1fr` gap, then the action pinned to the last row.
 *
 * The spacer is a ROW rather than a `margin-top: auto` on the action, and the action is
 * placed with `grid-row: -1` rather than left to auto-placement. Both matter: a card whose
 * post has no image contributes one fewer child, and auto-placement would then land the
 * action in the spacer row and let the excerpt stretch. Pinning it to the end means the rows
 * of two cards beside each other line up whether or not either has an image — which is what
 * replaced the 450px floor, and unlike that floor it also holds for a card with MORE content.
 */
.cms-card-inner {
    display: grid;
    grid-template-rows: repeat(4, auto) 1fr auto;
    gap: 12px;
    padding: 24px;
    height: 100%;
}

/* Whatever closes the card sits in the last row: the decorative "read more" row on a post
 * card, or a real button on a library card, where the action is the tap target itself. */
.cms-card-inner > .cms-card-action,
.cms-card-inner > .cms-btn {
    grid-row: -1;
}

/* A card-closing button is sized by its row, not stretched across it. */
.cms-card-inner > .cms-btn {
    justify-self: start;
}

/*
 * A card with no image reserves nothing: the media row collapses and the text starts at the
 * top of the card (AC-10). That is what `auto` rows give for free and what a fixed media box
 * would not.
 */
.cms-card-media {
    border-radius: 0;
}

.cms-card-meta {
    font-size: var(--seef-core-small-size);
    color: var(--seef-core-text-muted);
}

.cms-card-title {
    margin: 0;
    font-family: var(--seef-core-font-display);
    font-size: var(--seef-core-h3-size);
    font-weight: var(--seef-core-h3-weight);
    line-height: 1.4;
    color: var(--seef-core-text);
    transition: var(--seef-core-transition);
    text-wrap: pretty;
}

/*
 * The excerpt clamps to three LINES, not to 100 characters. A character count cuts mid-word
 * and, in Arabic, mid-ligature; a line clamp cuts where the line already ended.
 */
.cms-card-excerpt {
    margin: 0;
    font-size: var(--seef-core-small-size);
    line-height: var(--seef-core-small-leading);
    color: var(--seef-core-text-muted);
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    overflow: hidden;
}

/*
 * The whole card is the link, so the action row is decoration inside it rather than a target
 * of its own — which is how a 44px floor is met without a 44px button. It is pushed to the
 * bottom by the `1fr` row above it, not by `margin-top: auto` on a flex child.
 */
.cms-card-action {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: var(--seef-core-small-size);
    font-weight: 500;
    color: var(--seef-core-primary-text);
}

/*
 * The reading column caps the POST, not just its prose.
 *
 * `.cms-prose` alone would cap the text and leave the illustration floating at 50% of the full
 * container — half of 1152px beside a 68ch column, which is an illustration wider than the text
 * it belongs to. Capping the post means the float is half of the reading column, which is what
 * artboard 05 draws.
 */
.cms-post {
    max-width: var(--seef-core-prose-max);
}

.cms-post-media,
.cms-hero-media {
    border-radius: var(--seef-core-radius-media);
}

.cms-hero-media {
    width: 100%;
}

/*
 * The stand-in behind a hero with no image uploaded. A flat recessed surface, never a
 * gradient of the brand: a gradient has no single colour underneath it, so no text placed on
 * it has a contrast ratio that can be measured — the reason `funky`'s page gradient went too.
 */
.cms-hero-placeholder {
    background-color: var(--seef-core-surface-sunken);
}

/* ---------------------------------------------------------------------------
 * The page-builder frame
 * ------------------------------------------------------------------------- */

.cms-widget-grid {
    max-width: var(--seef-core-container);
    margin-left: auto;
    margin-right: auto;
    padding-inline: var(--seef-core-gutter);
    padding-block: var(--seef-core-section-py);
}

.cms-widget-block + .cms-widget-block {
    margin-top: var(--seef-core-block-gap);
}


/*
 * A block's title is part of the design and the visitor sees it — but it is rendered by the
 * BLOCK, through the section-header component, not by the page-builder frame.
 *
 * `.cms-widget-title` and its four tokens used to paint a second `<h2>` that the frame emitted
 * above every block, alongside the header the block drew for itself. The duplicate was
 * invisible only because the default theme set `--seef-core-widget-title-display: none`; showing
 * block titles (§9.9) put every title on the page twice. The design says which one survives:
 * "every block already runs its title through one section-header component" — and that
 * component carries the optional eyebrow and description, which a bare heading could not.
 *
 * So the per-skin knob the skin map calls `--widget-title` is `.cms-section-header`'s own
 * `--seef-core-h2-*` tokens, which every theme already declares and varies.
 */
/* ---------------------------------------------------------------------------
 * Editor-authored body copy
 * ------------------------------------------------------------------------- */

.cms-prose {
    color: var(--seef-core-text);
    font-size: var(--seef-core-body-size);
    line-height: var(--seef-core-body-leading);
    max-width: var(--seef-core-prose-max);
}

.cms-prose h2 {
    font-family: var(--seef-core-font-display);
    font-size: var(--seef-core-h2-size);
    font-weight: var(--seef-core-h2-weight);
    line-height: var(--seef-core-h2-leading);
    margin: 32px 0 12px;
}

.cms-prose h3 {
    font-family: var(--seef-core-font-display);
    font-size: var(--seef-core-h3-size);
    font-weight: var(--seef-core-h3-weight);
    margin: 24px 0 12px;
}

.cms-prose p {
    margin: 0 0 24px;
}

.cms-prose a {
    color: var(--seef-core-primary-text);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.cms-prose blockquote {
    border-inline-start: 3px solid var(--seef-core-primary);
    background-color: var(--seef-core-surface-sunken);
    padding: 16px 24px;
    margin: 24px 0;
}

/*
 * A wide table scrolls inside its own box — `_layout.css` owns that. What belongs here is
 * what it looks like: a header row on the brand tint, which is 10% of the primary over the
 * surface and therefore pairs with full-strength ink at AA for any client hue.
 */
.cms-prose th {
    background-color: var(--seef-core-primary-tint);
    color: var(--seef-core-text);
    font-weight: 500;
    text-align: start;
}

.cms-prose th,
.cms-prose td {
    padding: 12px 16px;
    border: var(--seef-core-hairline-width) solid var(--seef-core-line);
}

/* An optional caption under a post illustration. Absent field, absent row. */
.cms-media-caption {
    margin-top: 8px;
    font-size: var(--seef-core-small-size);
    color: var(--seef-core-text-muted);
}

/* ---------------------------------------------------------------------------
 * Controls — one button, three ranks
 *
 * This replaces four near-identical pills and a `rounded-sm!` Flux override. Height 44px,
 * radius `--seef-core-radius-control`, label 15/600, padding s5. The pill shape is for round icon
 * buttons and the type badge only; a text button is never a pill.
 * ------------------------------------------------------------------------- */

.cms-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 44px;
    padding: 0 24px;
    border: var(--seef-core-btn-border);
    border-radius: var(--seef-core-radius-control);
    font-size: var(--seef-core-small-size);
    font-weight: 600;
    line-height: 1;
    text-decoration: none;
    cursor: pointer;
    transition: var(--seef-core-transition);
}

.cms-btn--primary {
    background-color: var(--seef-core-primary);
    color: var(--seef-core-on-primary);
}

.cms-btn--primary:hover {
    background-color: var(--seef-core-primary-hover);
    /* No second computation needed: darkening only raises the ink's contrast. */
    color: var(--seef-core-on-primary);
}

.cms-btn--secondary {
    background-color: var(--seef-core-surface);
    color: var(--seef-core-text);
    border-color: var(--seef-core-line-strong);
}

.cms-btn--secondary:hover {
    border-color: var(--seef-core-primary);
    color: var(--seef-core-primary-text);
}

/* Tertiary is the text rank: a label and a logical chevron, no box until it is focused. */
.cms-btn--tertiary {
    background-color: transparent;
    border-color: transparent;
    padding: 0 8px;
    color: var(--seef-core-primary-text);
}

.cms-btn--tertiary:hover {
    text-decoration: underline;
    text-underline-offset: 3px;
}

.cms-btn:disabled,
.cms-btn[aria-disabled='true'] {
    opacity: 0.5;
    cursor: not-allowed;
}

/*
 * On the inverse band a primary-filled button can fall below 3:1 against the ground for a
 * dark client primary, so the CTA's button inverts instead: the band's own ink as the fill,
 * the band as the label. Both sides are already measured against each other.
 */
.cms-footer-cta .cms-btn--primary,
.cms-contact-banner .cms-btn--primary {
    background-color: var(--seef-core-text-on-cta);
    color: var(--seef-core-cta-surface);
}

/* ---------------------------------------------------------------------------
 * Chip — category filter, tag, post-header category
 * ------------------------------------------------------------------------- */

.cms-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 32px;
    padding: 4px 12px;
    border-radius: var(--seef-core-radius-pill);
    border: var(--seef-core-hairline-width) solid var(--seef-core-line);
    background-color: var(--seef-core-surface);
    color: var(--seef-core-text-muted);
    font-size: var(--seef-core-small-size);
    font-weight: var(--seef-core-label-weight);
    text-decoration: none;
    transition: var(--seef-core-transition);
}

.cms-chip:hover {
    background-color: var(--seef-core-primary);
    border-color: var(--seef-core-primary);
    color: var(--seef-core-on-primary);
}

/* The selected filter. `aria-current` is the same state, so it carries the same paint. */
.cms-chip--selected,
.cms-chip[aria-current] {
    background-color: var(--seef-core-primary);
    border-color: var(--seef-core-primary);
    color: var(--seef-core-on-primary);
}

/* Secondary copy: the replacement for a Tailwind colour name this package never declared. */
.cms-muted {
    color: var(--seef-core-text-muted);
}

/*
 * The one place a brand-coloured word appears inside a sentence — the rotating hero word and
 * the CTA's highlighted noun. It is `--seef-core-primary-text` with no plate behind it, so the
 * static state reads on its own, and it is NOT bolded: the colour is the emphasis.
 */
.cms-brand-text {
    color: var(--seef-core-primary-text);
    font-weight: inherit;
}

/* On the inverse band there is no clamped-primary ink that is guaranteed legible, so the
 * highlight falls back to the band's own computed ink. */
.cms-footer-cta .cms-brand-text,
.cms-contact-banner .cms-brand-text {
    color: var(--seef-core-text-on-cta);
}

/*
 * Icon pills on the numbers block and the library card. This is the element that replaced the
 * `light-green` / `dark-green` pair — two literals from one client's brand that every other
 * client inherited. Tint fill, clamped-primary glyph: AA at any hue.
 */
.cms-icon-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: var(--seef-core-radius-pill);
    background-color: var(--seef-core-primary-tint);
    color: var(--seef-core-primary-text);
}

/* ---------------------------------------------------------------------------
 * Library card — type badge, one action per type
 * ------------------------------------------------------------------------- */

.cms-type-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 8px;
    border-radius: var(--seef-core-radius-pill);
    background-color: var(--seef-core-primary-tint);
    color: var(--seef-core-primary-text);
    font-family: var(--seef-core-font-mono);
    font-size: var(--seef-core-label-size);
    font-weight: var(--seef-core-label-weight);
    letter-spacing: var(--seef-core-label-tracking);
}

/*
 * Format and size, in mono and always left-to-right — a visitor on a metered connection
 * decides with this line, so it sits immediately before the action.
 */
.cms-file-meta {
    font-family: var(--seef-core-font-mono);
    font-size: var(--seef-core-label-size);
    color: var(--seef-core-text-muted);
}

/* ---------------------------------------------------------------------------
 * Number card and partner tile
 * ------------------------------------------------------------------------- */

.cms-number-figure {
    font-family: var(--seef-core-font-display);
    font-size: var(--seef-core-display-size);
    font-weight: var(--seef-core-h1-weight);
    line-height: 1.1;
    color: var(--seef-core-text);
}

.cms-number-label {
    font-size: var(--seef-core-small-size);
    color: var(--seef-core-text-muted);
}

.cms-partner-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 104px;
    padding: 16px;
    border: var(--seef-core-card-border);
    border-radius: var(--seef-core-radius-card);
    background-color: var(--seef-core-surface);
}

.cms-partner-tile img {
    max-width: 40px;
    max-height: 24px;
    object-fit: contain;
}

/* The caption wraps to two lines rather than truncating — a partner's name is not decoration. */
.cms-partner-name {
    font-size: var(--seef-core-label-size);
    color: var(--seef-core-text-muted);
    text-align: center;
}

/* ---------------------------------------------------------------------------
 * Accordion — FAQ
 *
 * Exclusive, 56px rows, a hairline between items, and no box inside a box: the answer sits in
 * the same surface as the question rather than in a nested card.
 * ------------------------------------------------------------------------- */

.cms-accordion {
    border: var(--seef-core-card-border);
    border-radius: var(--seef-core-radius-card);
    background-color: var(--seef-core-surface);
    overflow: hidden;
}

.cms-accordion-item + .cms-accordion-item {
    border-top: var(--seef-core-hairline-width) solid var(--seef-core-line);
}

.cms-accordion-trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    width: 100%;
    min-height: 56px;
    padding: 12px 24px;
    background: none;
    border: 0;
    text-align: start;
    font-size: var(--seef-core-body-size);
    color: var(--seef-core-text);
    cursor: pointer;
    transition: var(--seef-core-transition);
}

.cms-accordion-trigger:hover {
    color: var(--seef-core-primary-text);
}

/*
 * `flex: none` on the sign is what lets a long question wrap without pushing the +/− off the
 * end of the row — the failure the 360 board is drawn to show.
 */
.cms-accordion-sign {
    flex: none;
    color: var(--seef-core-text-muted);
}

.cms-accordion-panel {
    padding: 0 24px 24px;
    max-width: var(--seef-core-prose-max);
    font-size: var(--seef-core-body-size);
    line-height: var(--seef-core-body-leading);
    color: var(--seef-core-text-muted);
}

/*
 * THE SAME ANATOMY, ATTACHED TO FLUX'S ELEMENTS.
 *
 * The accordion itself is `<flux:accordion>`, so the rows above are described against classes
 * that are never on the page: Flux renders `ui-disclosure` elements of its own and sizes them
 * with its own utilities. The result was a 16px row where the design asks for 56px and s5 —
 * cramped enough to be reported as the section looking wrong.
 *
 * Keyed on Flux's data attributes, which are the part of its markup meant to be addressed;
 * class names in its output are compiled utilities and are not a contract. `button` narrows
 * the heading rule because Flux puts `data-flux-accordion-heading` on the group as well as on
 * each button, and the group must not gain a row's height.
 */
.cms-accordion [data-flux-accordion-item] {
    padding-inline: 24px;
}

.cms-accordion button[data-flux-accordion-heading] {
    min-height: 56px;
    padding-block: 16px;
    /* The question is body copy, not a heading: weight 600 is the page title and buttons. */
    font-size: var(--seef-core-body-size);
    font-weight: 500;
    line-height: 1.5;
    color: var(--seef-core-text);
}

.cms-accordion [data-flux-accordion-content] {
    padding-bottom: 24px;
    max-width: var(--seef-core-prose-max);
    font-size: var(--seef-core-body-size);
    line-height: var(--seef-core-body-leading);
    color: var(--seef-core-text-muted);
}

/* ---------------------------------------------------------------------------
 * Form fields
 *
 * 48px rather than the button's 44 — comfortable for typing, and still one step on the same
 * scale. The label sits above the field; a placeholder is never the only label.
 * ------------------------------------------------------------------------- */

/* The form column: the reading measure, not a third of the screen. */
.cms-form-column {
    max-width: var(--seef-core-prose-max);
}

.cms-field {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.cms-label {
    font-size: var(--seef-core-small-size);
    font-weight: 500;
    color: var(--seef-core-text);
}

.cms-input,
.cms-textarea,
.cms-select {
    width: 100%;
    min-height: 48px;
    padding: 12px 16px;
    background-color: var(--seef-core-surface);
    color: var(--seef-core-text);
    border: var(--seef-core-hairline-width) solid var(--seef-core-line);
    border-radius: var(--seef-core-radius-control);
    font-family: inherit;
    font-size: var(--seef-core-body-size);
    line-height: 1.5;
    transition: var(--seef-core-transition);
}

.cms-textarea {
    min-height: 144px;
    resize: vertical;
}

/*
 * The one state a visitor must be able to read before they have typed anything. At 62% of the
 * ink over the surface it measures 5.0:1 — one step weaker than a filled value and still AA.
 * The `#9CA3AF`-class grey this replaces measures 2.5:1 and is not allowed anywhere.
 */
.cms-input::placeholder,
.cms-textarea::placeholder {
    color: var(--seef-core-text-placeholder);
    opacity: 1;
}

/*
 * Error red is the one hue outside the client's palette: it is a system state, not a brand
 * colour, so it does not re-map per skin. Colour is never the only signal — the border
 * thickens and a message with a glyph appears beneath the field.
 */
.cms-input[aria-invalid='true'],
.cms-textarea[aria-invalid='true'],
.cms-select[aria-invalid='true'] {
    border-width: 2px;
    border-color: #B91C1C;
}

.cms-field-error {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: var(--seef-core-small-size);
    color: #B91C1C;
}

/* ---------------------------------------------------------------------------
 * Social buttons — one component, two shapes
 *
 * 44px in both. They were 32px, which is below the tap-target floor; the footer's are square
 * and the sticky rail's are round, and that is the only difference between them.
 * ------------------------------------------------------------------------- */

.cms-social {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: var(--seef-core-radius-control);
    border: var(--seef-core-hairline-width) solid var(--seef-core-line);
    transition: var(--seef-core-transition);
}

.cms-footer .cms-social {
    border-color: var(--seef-core-text-on-inverse);
    color: var(--seef-core-text-on-inverse);
}

/*
 * The sticky rail floats above the page rather than sitting in it, so it is one of the three
 * surfaces allowed the overlay shadow.
 */
.cms-sticky-socials a {
    background-color: var(--seef-core-surface);
    border: var(--seef-core-hairline-width) solid var(--seef-core-line);
    border-radius: var(--seef-core-radius-pill);
    box-shadow: var(--seef-core-shadow-overlay);
    transition: var(--seef-core-transition);
}

/* ---------------------------------------------------------------------------
 * Overlays — the only surfaces with depth
 *
 * The nav dropdown, the mobile sidebar and the pop-over panel. Everything else in the system
 * is separated by a line, so a client whose brand is flat never fights a shadow.
 * ------------------------------------------------------------------------- */

.cms-dropdown,
.cms-popover-panel {
    background-color: var(--seef-core-surface);
    border: var(--seef-core-hairline-width) solid var(--seef-core-line);
    border-radius: var(--seef-core-radius-card);
    box-shadow: var(--seef-core-shadow-overlay);
}

/* ---------------------------------------------------------------------------
 * Empty states
 *
 * Never a bare "no results": a tint disc, one line of explanation, and an action that leads
 * somewhere. A listing with nothing in it is a normal state of a CMS, not an error.
 * ------------------------------------------------------------------------- */

.cms-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
    padding: 48px 24px;
    text-align: center;
    color: var(--seef-core-text-muted);
}

.cms-empty-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 64px;
    height: 64px;
    border-radius: var(--seef-core-radius-pill);
    background-color: var(--seef-core-primary-tint);
    color: var(--seef-core-primary-text);
}

/* ---------------------------------------------------------------------------
 * Phone rhythm
 *
 * The only responsive rules in this file, and they are about breathing room rather than
 * arrangement — everything structural stays in `_layout.css`.
 * ------------------------------------------------------------------------- */

@media (max-width: 1279px) {
    .cms-hero,
    .cms-section,
    .cms-widget-grid {
        padding-top: var(--seef-core-section-py-tablet);
        padding-bottom: var(--seef-core-section-py-tablet);
    }

    .cms-widget-grid {
        padding-inline: var(--seef-core-gutter-tablet);
    }
}

@media (max-width: 767px) {
    .cms-hero,
    .cms-section,
    .cms-widget-grid {
        padding-top: var(--seef-core-section-py-phone);
        padding-bottom: var(--seef-core-section-py-phone);
    }

    .cms-widget-grid {
        padding-inline: var(--seef-core-gutter-phone);
    }

    .cms-card-inner {
        padding: 16px;
    }

    /*
     * A button that is the whole tap target on a phone spans the column and grows a step.
     * `max-width` as well as `width`, because a flex or grid parent can hand a child a basis
     * wider than the column and `width: 100%` would then resolve against that.
     */
    .cms-btn {
        width: 100%;
        max-width: 100%;
        min-height: 48px;
    }

    .cms-btn--tertiary {
        width: auto;
    }
}

/* ---------------------------------------------------------------------------
 * Reduced motion
 *
 * Disables every transition, the hero's word swap (the last word simply stays) and the
 * partners marquee. The marquee's own animation is declared in `_layout.css`; this is the
 * blanket rule that catches anything else.
 * ------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    .cms-body *,
    .cms-body *::before,
    .cms-body *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* ---------------------------------------------------------------------------
 * البوابة's two blocks — the shortcut panel and the shortcut strip
 *
 * Their markup is shared by every template (ADR-0009) and so are these rules. Everything
 * here describes the components themselves; the one thing that is a property of البوابة
 * rather than of them — the strip lifting over the hero's lower edge — is keyed on a
 * modifier class only البوابة's own copy of the view emits, so it simply never matches
 * under Classic rather than being scoped to a template attribute. That is the same
 * convention the rest of this file follows: a component is described once, by its class,
 * and a class exists on the page only when a view wrote it.
 * ------------------------------------------------------------------------- */

.cms-login-panel-card {
    max-width: 34rem;
    margin-inline: auto;
}

.cms-login-panel-rows {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/*
 * A row is a link and is a tap target, so it clears the 44px floor on its own. The label
 * takes the free space and the note is pushed to the inline end, which is what makes the
 * two read as a pair rather than as a sentence.
 */
.cms-login-panel-row {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 44px;
    padding: 12px;
    border-radius: var(--seef-core-radius-control);
    background-color: var(--seef-core-surface-sunken);
    color: var(--seef-core-text);
    font-weight: 600;
    text-decoration: none;
    transition: var(--seef-core-transition);
}

.cms-login-panel-row:hover {
    background-color: var(--seef-core-primary-tint);
    color: var(--seef-core-primary-text);
}

.cms-login-panel-row-label {
    flex: 1;
    min-width: 0;
}

.cms-login-panel-row-note {
    flex: none;
    font-weight: 400;
    font-size: var(--seef-core-label-size);
    color: var(--seef-core-text-muted);
}

/* The panel's call to action fills the card's width — it is the one thing the panel asks
 * for, and `.cms-card-inner > .cms-btn` would otherwise size it to its label. */
.cms-card-inner > .cms-login-panel-action {
    justify-self: stretch;
    width: 100%;
}

.cms-login-panel-note {
    margin: 0;
    font-size: var(--seef-core-label-size);
    text-align: center;
    color: var(--seef-core-text-muted);
}

.cms-login-panel-note a {
    color: var(--seef-core-primary-text);
    text-decoration: underline;
    text-underline-offset: 3px;
}

/*
 * A strip card is one row of content, so it overrides the six-row card grid rather than
 * leaving four empty tracks between its icon and its label.
 */
.cms-quick-links-item {
    text-decoration: none;
    color: var(--seef-core-text);
}

.cms-quick-links-item-inner {
    display: flex;
    align-items: center;
    gap: 14px;
    height: auto;
}

.cms-quick-links-item-label {
    font-weight: 600;
    min-width: 0;
}

/*
 * The two modifier classes **only البوابة's copies of those views emit**.
 *
 * They are here, with the component, rather than in the kernel's `portal.css`, and the
 * difference is not filing. A rule keyed on a modifier is inert until a view writes the
 * modifier, so this file describes each component once and no rule has to be scoped to a
 * template attribute — which is the arrangement the per-appearance blocks were collapsed into
 * in feature 017, and what stops a component starting to be described per template again.
 *
 * Every value below is a `--seef-core-*` token, so both are painted from the client's brand
 * under whatever template emits them.
 */

/* The gradient band behind the shortcut panel — the design's hero. Its ink is white by
 * construction: `--seef-core-surface-brand` is the client's colour clamped until white clears
 * 4.5:1 on it, whatever they typed. */
.cms-login-panel--hero {
    background-color: var(--seef-core-surface-brand);
    background-image: linear-gradient(
        115deg,
        var(--seef-core-surface-brand-deep) 0%,
        var(--seef-core-surface-brand) 100%
    );
    color: var(--seef-core-on-surface-brand);
    padding-block: var(--seef-core-section-py-tablet) calc(var(--seef-core-section-py) + 40px);
}

.cms-login-panel-hero-inner {
    display: grid;
    grid-template-columns: 1fr;
    gap: 32px;
    align-items: center;
}

@media (min-width: 1024px) {
    .cms-login-panel-hero-inner {
        grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
        gap: 56px;
    }
}

.cms-login-panel-intro-title {
    margin: 0;
    font-family: var(--seef-core-font-display);
    font-size: var(--seef-core-display-size);
    font-weight: var(--seef-core-h1-weight);
    line-height: var(--seef-core-h1-leading);
    color: var(--seef-core-on-surface-brand);
    text-wrap: pretty;
}

.cms-login-panel-intro-text {
    margin: 18px 0 0;
    max-width: 40rem;
    line-height: var(--seef-core-body-leading);
    color: var(--seef-core-on-surface-brand);
}

/* Inside the band the card is the band's column, not a centred measure of its own. */
.cms-login-panel--hero .cms-login-panel-card {
    max-width: none;
    margin-inline: 0;
}

/*
 * AC-16 — the strip lifts over the band's lower edge at the desktop width and does not at 360.
 *
 * `margin-block-start`, not `margin-top`: this package's arrangement is written in logical
 * properties throughout. The lift is `-72px`, the design's own figure, and the band above
 * reserves it in its own bottom padding so the lift takes space that was left for it rather
 * than space something else was using.
 */
.cms-quick-links--overlap {
    position: relative;
    z-index: 5;
    padding-block-start: 0;
}

@media (min-width: 1024px) {
    .cms-quick-links--overlap {
        margin-block-start: -72px;
    }
}

/*
 * البوابة's landing frame runs its bands edge to edge (feature 029, T061). Classic's is a
 * measured column with gutters; each block already carries its own `.container`, so what this
 * removes is a second, outer measure and not the blocks' own.
 */
.cms-widget-grid--full {
    max-width: none;
    padding-inline: 0;
}

/*
 * Responsive layout — feature 013, ADR-0001.
 *
 * UNSCOPED ON PURPOSE. The theme files beside this one are each scoped to a single theme
 * because they declare colour and surface values, which differ per theme. Arrangement does
 * not: a listing collapses to one column on a phone whichever theme is selected. So these
 * rules carry no theme scope, and all three variants get them from one source rather than
 * from three copies drifting apart.
 *
 * `_base.css` is unscoped for the same class of reason — it describes which element is a
 * surface and which carries a border, which is also the same under every theme; only the
 * values differ, and those are what the theme files declare. See feature 017, ADR-0001.
 *
 * Named with a leading underscore so it sorts first in the concatenation the stylesheet
 * route serves — base arrangement first, theme colour after.
 *
 * Why arrangement lives here at all, rather than in Tailwind utilities in the Blade views:
 * a consuming project's build does not necessarily scan this package's views. `vendor/` is
 * normally git-ignored, which Tailwind 4's source detection skips, so utilities used only
 * here may compile to nothing on a client site. Measured on a real consumer: `sm:grid-cols`
 * present in its bundle, `md:grid-cols` absent. Rules in this file need no build anywhere.
 * See docs/responsive-layout.md.
 */

/* ---------------------------------------------------------------------------
 * Nothing exceeds the screen (AC-01, AC-08)
 *
 * Editor-authored content is arbitrary — a post body can carry an image wider than the
 * phone, a table of twelve columns, an embedded video sized for a desktop, or an unbroken
 * 100-character URL. None of it has classes of ours, so it is constrained at the container.
 * ------------------------------------------------------------------------- */

.cms-body img,
.cms-body video,
.cms-body iframe,
.cms-body embed,
.cms-body object {
    max-width: 100%;
}

/*
 * SCOPED TO THE CONTENT, NOT TO THE WHOLE BODY — and the difference is not cosmetic.
 *
 * This file is served unlayered and Tailwind's utilities sit in `@layer utilities`, so an
 * unlayered `height` here beats every `h-*` in the markup whatever its specificity. On
 * `.cms-body` that reached the SHELL's own images: the mobile menu's brand logo is sized `h-6`
 * by Flux, this rule freed it, and the logo rendered at its full intrinsic height and stretched
 * the brand row. Reported from a live site.
 *
 * The guard exists for editor-authored content, which is arbitrary and carries no classes of
 * ours. That content is inside `<main class="cms-main">`. The shell's chrome is ours and is
 * sized below, so it needs no guard and must not be given one.
 *
 * `max-width: 100%` above stays on `.cms-body`: it can only prevent overflow, never cause it.
 */
.cms-main img,
.cms-main video {
    height: auto;
}

/* ---------------------------------------------------------------------------
 * The shell's own images, sized here rather than in the markup
 *
 * The header logo, the mobile menu's brand and the footer logo were sized with `w-[80px]`,
 * `h-6` and `w-[120px]` — Tailwind utilities, which a consuming project's build does not
 * necessarily compile out of this package's views. Where they do not compile, a client's logo
 * renders at whatever size it was uploaded at and stretches the shell around it. The cap is
 * stated here, where it needs no build; `width: auto` keeps the aspect ratio of a wordmark.
 * ------------------------------------------------------------------------- */

.cms-header img,
[data-flux-sidebar] [data-flux-sidebar-brand] img {
    max-height: 40px;
    width: auto;
    object-fit: contain;
}

.cms-footer img {
    max-height: 48px;
    width: auto;
    object-fit: contain;
}

/* A long unbroken URL is the one case `overflow-wrap: break-word` alone does not catch. */
.cms-prose {
    overflow-wrap: anywhere;
}

/*
 * A wide table cannot be made narrow without destroying it, so it scrolls inside its own
 * box. This is the same principle as the deliberate scrollers: the component may scroll,
 * the page may not.
 */
.cms-prose table {
    display: block;
    max-width: 100%;
    overflow-x: auto;
}

/* ---------------------------------------------------------------------------
 * Listings (AC-04, AC-05)
 *
 * One item per row on a phone, widening in steps that never reduce. The desktop steps
 * reproduce what the twelve-column grid produced before this feature — two per row from
 * the tablet width, three from 1024, four from 1280 — so AC-03 and AC-13 hold.
 * ------------------------------------------------------------------------- */

.cms-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
}

@media (min-width: 768px) {
    .cms-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 1024px) {
    .cms-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

@media (min-width: 1280px) {
    .cms-grid {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}

/* `minmax(0, 1fr)` above is what stops a wide child stretching its own column. */
.cms-grid > * {
    min-width: 0;
}

/*
 * Scoped through `.cms-body` for specificity, not for reach.
 *
 * The editor-content guard above sets `height: auto` on `.cms-body img` — one class and one
 * type, 0-1-1 — which outranks a bare `.cms-card-media` at 0-1-0. So this rule has never
 * applied on a real page since it was written: card images have rendered at their intrinsic
 * height throughout, which on a site whose posts carry portrait posters made every card
 * roughly a thousand pixels tall. Matching the guard's specificity is what makes the
 * declared height real.
 */
.cms-body .cms-card-media {
    width: 100%;
    height: 180px;
    object-fit: cover;
}

/* ---------------------------------------------------------------------------
 * Post details (AC-02, AC-03)
 *
 * The illustration stacks above the body on a phone. From the tablet width it floats at half
 * width, which is the arrangement that shipped before this feature — `float` rather than a
 * flex row deliberately, because floating lets the text wrap beneath the illustration and a
 * two-column flex does not. AC-03 asks for desktop to be unchanged, not merely similar.
 *
 * LOGICAL VALUES, AND DELIBERATELY SO — this reverses what feature 013 shipped.
 *
 * 013 used Tailwind's physical `float-left` and `mr-4`, so the illustration sat on the left
 * of the article whatever the text direction, and it kept that value on the stated grounds
 * that "desktop is unchanged". The design settles the question the other way
 * (`design/cms-public-site-canvas/…Public Site.dc.html`, artboard 05): reading starts at the
 * inline-start corner, so the image belongs there — the eye drops headline → picture → text.
 * Floating it physically left in an RTL document puts the illustration at the END of the
 * first line, which is why the pre-013 layout read as broken in the first place. The promise
 * of "desktop unchanged" was a promise about the wrong thing.
 *
 * This does move the illustration on every existing post at upgrade, which is a visible
 * change and belongs in the release notes.
 *
 * The browser floor 013 avoided is now accepted: `float: inline-start` needs Chrome 118+,
 * Safari 17.4+ and Firefox 129+, and anything older drops the declaration and stacks the
 * illustration at desktop too. That degradation is the phone layout, which is legible — and
 * the same floor already applies to the logical margins and `:dir()` selectors this
 * stylesheet relies on elsewhere.
 *
 * `DesktopArrangementTest` asserts the side, not merely that it floats. Asserting only
 * "it floats, and the body is beside it" is true of both arrangements, which is how the
 * regression that comment described reached review; the assertion is kept, with the side
 * flipped.
 * ------------------------------------------------------------------------- */

.cms-post-media {
    display: block;
    float: none;
    width: 100%;
    height: auto;
    margin: 0 0 1rem;
}

@media (min-width: 768px) {
    .cms-post-media {
        float: inline-start;
        width: 50%;
        /* s5 on the inline end, s4 below — the values the 768 artboard is drawn with. */
        margin-inline-end: 1.5rem;
        margin-bottom: 1rem;
    }
}

/*
 * The illustration fills the figure that floats.
 *
 * `.cms-post-media` is a `<figure>` now, because the caption has to travel with the picture.
 * That put an element between the float and the image, so the image needed a width of its own
 * — and it was carrying Tailwind's `w-full`, which is exactly the kind of utility a consuming
 * project's build does not compile out of `vendor/`. Stated here, it needs no build anywhere.
 */
.cms-post-media img {
    display: block;
    width: 100%;
    height: auto;
}

/* The body clears the floated illustration so a short post cannot leave them overlapping. */
.cms-post::after {
    content: '';
    display: block;
    clear: both;
}

/* ---------------------------------------------------------------------------
 * Deliberate horizontal scrollers — the closed exemption list (grill D2)
 *
 * These three express their arrangement AS horizontal scrolling, and they work correctly
 * at phone width. They are exempt from the one-item-per-row rule; they are NOT exempt from
 * AC-01, which is asserted on the document. The component may scroll; the page may not.
 *
 * The rules live here for the same reason as everything else in this file: expressed as
 * `overflow-x-auto` utilities they would depend on a consuming project's build compiling
 * them, and a swipe row that silently stops scrolling is a worse defect than one that
 * never worked.
 * ------------------------------------------------------------------------- */

.cms-scroller {
    display: flex;
    gap: 1rem;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
}

.cms-scroller > * {
    flex: 0 0 auto;
    scroll-snap-align: start;
}

.cms-numbers--row .cms-scroller > * {
    min-width: 220px;
}

/* The partners marquee is clipped rather than scrolled — it moves on its own. */
.cms-partners--carousel .cms-scroller {
    overflow-x: hidden;
    scroll-snap-type: none;
}

/* ---------------------------------------------------------------------------
 * The partners marquee
 *
 * One of the three exempt scrollers, and the only one that moves on its own. The animation
 * lived in the markup as `animate-marquee` — a Tailwind utility this package never defined
 * and a consuming project's build would not compile from `vendor/`, so on a client site the
 * row simply stood still. It belongs here for the same reason everything else does: a rule in
 * this file needs no build anywhere.
 *
 * The track holds the partner list three times over, so translating it by exactly one third
 * returns it to its starting position and the loop is seamless.
 * ------------------------------------------------------------------------- */

@keyframes cms-marquee {
    from {
        transform: translateX(0);
    }

    to {
        transform: translateX(calc(-100% / 3));
    }
}

/*
 * The BAND clips, and the track is as wide as its content.
 *
 * Both halves matter. A track at the container's width cannot be translated seamlessly — it
 * would have to know how wide its own content is — so it takes `max-content`. But a
 * `max-content` track is then wider than the phone, and clipping it on the track itself does
 * nothing: the element is still 554px wide in a 360px viewport and the DOCUMENT scrolls. The
 * clip has to be on an ancestor that is the width of the screen.
 */
.cms-partners--carousel {
    overflow: hidden;
}

.cms-partners--carousel .cms-scroller {
    animation: cms-marquee 40s linear infinite;
    width: max-content;
    max-width: none;
}

/*
 * NO PAUSE ON HOVER. The design asks for one — "pause on hover" — and it is deliberately not
 * implemented: the row spans the page, so on a wide screen a pointer resting anywhere near the
 * middle of the band stops it, and it reads as the animation having broken rather than as a
 * considerate pause. Asked for directly after seeing it on a live site.
 *
 * Focus still pauses it, which costs a mouse user nothing and lets a keyboard user stop on a
 * logo they are tabbing to. Note what this gives up: `prefers-reduced-motion` below is now the
 * only way a visitor can stop the row, which is the standard accommodation but not a control
 * they can reach from the page itself.
 */
.cms-partners--carousel:focus-within .cms-scroller {
    animation-play-state: paused;
}

/*
 * The logo size, stated here rather than as `h-[46px]` in the markup — an arbitrary-value
 * utility is exactly the kind a consuming project's build does not compile out of `vendor/`,
 * and an unsized logo in a marquee is a row of full-resolution images.
 */
.cms-partners--carousel .cms-scroller img {
    height: 36px;
    width: auto;
    object-fit: contain;
}

/*
 * Stopped, not merely slowed. `_base.css` collapses every animation duration under reduced
 * motion, which for an infinite loop would leave it spinning imperceptibly rather than
 * standing still; this stops the track outright.
 */
@media (prefers-reduced-motion: reduce) {
    .cms-partners--carousel .cms-scroller {
        animation: none;
    }
}

/* ---------------------------------------------------------------------------
 * Direction
 *
 * Everything above is specified logically, so an LTR site is a direction flip rather than a
 * redraw. Two things need saying explicitly.
 *
 * The chevron is ONE glyph, mirrored by direction. The markup used to pick between
 * `heroicon-o-arrow-long-left` and `-right` in PHP by reading Filament's layout direction,
 * which meant the icon was chosen server-side from a panel setting rather than from the
 * document's own direction — and got it wrong on any page rendered outside a panel request.
 * ------------------------------------------------------------------------- */

.cms-chevron {
    flex: none;
}

:dir(ltr) .cms-chevron {
    transform: scaleX(-1);
}

/*
 * A Latin run inside Arabic prose — a URL, an email address, a phone number, a file size —
 * carries `dir="ltr"` in the markup so the bidi algorithm does not reorder its punctuation.
 * `inline-block` keeps the isolated run from breaking the line box around it.
 */
.cms-body [dir='ltr'] {
    unicode-bidi: isolate;
}

/* ---------------------------------------------------------------------------
 * The sticky social rail
 *
 * Landing page only, and only from the tablet width up. On a phone a rail pinned over the
 * document is covering content rather than decorating it — there is no gutter to put it in.
 * ------------------------------------------------------------------------- */

@media (max-width: 767px) {
    .cms-sticky-socials {
        display: none;
    }
}

/* ---------------------------------------------------------------------------
 * A grid whose column count is chosen by how many items it holds
 *
 * `.cms-grid` widens in fixed steps — one, two, three, four — which is right for a listing,
 * where the count is whatever the CMS returns and a short last row is ordinary. It is wrong
 * for a block whose items are a set the editor wrote: six values in a four-column grid render
 * as four and then two, and the band reads as though something failed to load.
 *
 * The count is `--seef-core-grid-columns`, set inline on the element by `Seef\Cms\Support\
 * BalancedColumns` — an integer, not a class, because a class would have to be one of a fixed
 * set of Tailwind utilities and a consuming project's build does not compile utilities out of
 * this package's views.
 *
 * Only the desktop step varies. A phone is one column and a tablet two whatever the count.
 * ------------------------------------------------------------------------- */

.cms-grid--balanced {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
}

.cms-grid--balanced > * {
    min-width: 0;
}

@media (min-width: 768px) {
    .cms-grid--balanced {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 1024px) {
    .cms-grid--balanced {
        grid-template-columns: repeat(var(--seef-core-grid-columns, 3), minmax(0, 1fr));
    }
}

/* ---------------------------------------------------------------------------
 * Filament's screen-reader-only class, on the PUBLIC site
 *
 * The contact form is a Filament schema, so its fields arrive wrapped in Filament's own
 * markup — and a field marked `->hiddenLabel()` renders its label with `class="fi-sr-only"`
 * rather than not rendering it, which is correct: the label belongs in the accessibility tree
 * even when it is not drawn.
 *
 * `fi-sr-only` is defined in Filament's PANEL stylesheet, and the public site does not load
 * it. So the class resolved to nothing and the label was simply visible: every form page
 * showed a stray "Department id" above the department picker — reported from a live site.
 *
 * This is the same failure as every other one this stylesheet exists to prevent: markup on the
 * public site depending on a stylesheet that is not on the public site. The rule is the
 * standard visually-hidden recipe, which hides the label without removing it from the
 * accessibility tree — `display: none` would take it out of both.
 * ------------------------------------------------------------------------- */

.cms-body .fi-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/*
 * The floor: a value for every token the kernel's vocabulary declares (feature 029,
 * contract C-T5, ADR-0005 and ADR-0006).
 *
 * Served **first**, ahead of every contributed directory and ahead of the active template's
 * own block, so that three things are true whatever else is or is not installed:
 *
 * - A page renders correctly **before any brand value applies**. The shell writes the
 *   brand-derived tokens inline on `<html style="…">`, which is the last word in the
 *   cascade; this is what paints the page if that write is ever absent — a screen rendered
 *   outside the shell, an email body, a fragment fetched on its own.
 * - A **template that forgets a token** loses that token's value, not the page. Each
 *   template declares the whole set in its own block, and this file is what stands behind a
 *   missed one.
 * - A **consumer with no CMS installed** still gets a styled site. The structural rules live
 *   in `seef/cms-panel` (`_base.css`, `_layout.css`, ADR-0005), but the vocabulary they are
 *   written against is the kernel's and is declared here.
 *
 * Every name begins `--seef-core-`, the literal ADR-0006 fixes — matching the `seef-core::`
 * view and translation namespace, the `_seef-core/` routes and the `seef-core.site.*` config
 * keys. Custom properties only: `.cms-*` class names are `seef/cms-panel`'s and are untouched.
 *
 * The values below are the retired `default` skin's, which is the palette this workspace's
 * sites have actually been rendering. A floor that invented its own colours would make
 * "the token was missed" look like a deliberate design.
 */

:root {
    --seef-core-primary: #1D4ED8;
    --seef-core-primary-hover: #163EB0;
    --seef-core-primary-text: #1341CB;
    --seef-core-on-primary: #FFFFFF;
    --seef-core-primary-tint: color-mix(in srgb, var(--seef-core-primary) 10%, var(--seef-core-surface));
    --seef-core-page-bg: #FBFBFB;
    --seef-core-surface: #FFFFFF;
    --seef-core-surface-sunken: #F6F7F9;
    --seef-core-surface-inverse: #111827;
    --seef-core-surface-footer: var(--seef-core-surface-inverse);
    --seef-core-cta-surface: var(--seef-core-surface-inverse);
    --seef-core-text: #111827;
    --seef-core-text-muted: color-mix(in srgb, var(--seef-core-text) 70%, var(--seef-core-surface));
    --seef-core-text-placeholder: color-mix(in srgb, var(--seef-core-text) 62%, var(--seef-core-surface));
    --seef-core-text-on-inverse: #FFFFFF;
    --seef-core-text-on-cta: var(--seef-core-text-on-inverse);
    --seef-core-line: #E5E7EB;
    --seef-core-line-strong: color-mix(in srgb, var(--seef-core-text) 28%, var(--seef-core-surface));
    --seef-core-hairline-width: 1px;
    --seef-core-card-border: var(--seef-core-hairline-width) solid var(--seef-core-line);
    --seef-core-header-border: var(--seef-core-hairline-width) solid var(--seef-core-line);
    --seef-core-btn-border: 1px solid transparent;
    --seef-core-radius-control: 8px;
    --seef-core-radius-card: 12px;
    --seef-core-radius-media: 12px;
    --seef-core-radius-pill: 999px;
    --seef-core-shadow-overlay: 0 8px 32px rgb(0 0 0 / 0.16);
    --seef-core-section-py: 96px;
    --seef-core-section-py-tablet: 64px;
    --seef-core-section-py-phone: 48px;
    --seef-core-container: 1152px;
    --seef-core-gutter: 32px;
    --seef-core-gutter-tablet: 24px;
    --seef-core-gutter-phone: 16px;
    --seef-core-block-gap: 64px;
    --seef-core-prose-max: 68ch;
    --seef-core-font-body: 'IBM Plex Sans Arabic', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --seef-core-font-display: 'IBM Plex Sans Arabic', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --seef-core-font-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
    --seef-core-display-size: clamp(1.875rem, 1.4348rem + 1.9565vw, 3rem);
    --seef-core-h1-size: clamp(1.625rem, 1.3804rem + 1.087vw, 2.25rem);
    --seef-core-h1-weight: 600;
    --seef-core-h1-leading: 1.4;
    --seef-core-h2-size: 1.5rem;
    --seef-core-h2-weight: 500;
    --seef-core-h2-leading: 1.35;
    --seef-core-h3-size: 1.25rem;
    --seef-core-h3-weight: 500;
    --seef-core-body-size: 1.0625rem;
    --seef-core-body-leading: 1.85;
    --seef-core-small-size: 0.9375rem;
    --seef-core-small-leading: 1.7;
    --seef-core-label-size: 0.75rem;
    --seef-core-label-weight: 500;
    --seef-core-label-tracking: 0.08em;
    --seef-core-transition: color 120ms linear, background-color 120ms linear, border-color 120ms linear;
    --seef-core-focus-ring: 2px solid var(--seef-core-primary-text);
    --seef-core-focus-offset: 2px;

    /*
     * The accent, its ink and its ramp (feature 029, ADR-0004). New in this release: a
     * two-colour design needs a second brand value, and `BrandTokens` always returns one —
     * derived from the primary when the client set none — so no template ever branches on
     * "is there an accent" and no surface is left uncoloured.
     */
    --seef-core-accent: #A76416;
    --seef-core-accent-hover: #885010;
    --seef-core-accent-text: #824200;
    --seef-core-on-accent: #FFFFFF;

    /*
     * The ramp steps the two designs need, and no more. `design/templates/base.css` and
     * `a-platform.html` read five values off the teal — the base, `--teal-50`, `--teal-700`,
     * `--teal-800`, `--teal-900` — and four off the gold — the base, `--gold-50`,
     * `--gold-200`, `--gold-300`. Those are the steps here, under the kernel's own names.
     * A client cannot be asked to pick nine colours, and a template cannot ship one client's
     * nine as literals, so they are computed from the two the client did pick.
     */
    --seef-core-primary-50: #ECF2FE;
    --seef-core-primary-700: #072BA0;
    --seef-core-primary-800: #011580;
    --seef-core-primary-900: #010062;
    --seef-core-accent-50: #F8F2ED;
    --seef-core-accent-200: #DFC3AB;
    --seef-core-accent-300: #D1AA88;

    /*
     * A dark band in the client's hue, and the ink guaranteed legible on it (feature 029,
     * T052). Added with البوابة, whose gradient hero, counter band and footer are all
     * brand-coloured surfaces — which the ramp above cannot be, because `primary-900` scales
     * the client's own lightness and a pale brand's `900` is a mid-tone. See
     * `BrandTokens::surfaceBrand()`.
     */
    --seef-core-surface-brand: #1341CB;
    --seef-core-surface-brand-deep: #011283;
    --seef-core-on-surface-brand: #FFFFFF;
}

/*
 * classic — the token block of the retired `default` skin, moved here unchanged but for its
 * names (feature 029, ADR-0005, ADR-0006).
 *
 * Two things changed in the move and nothing else did. The selector is `:root` rather than
 * `[data-ui-theme='default']`, because a template is a Blade tree and a stylesheet rather
 * than an attribute on one tree — the attribute, the three skins and the environment variable
 * that chose between them all retire with this release. And every custom property is
 * `--seef-core-*` rather than `--cms-*`: the kernel computes these values now, and a name
 * claiming the CMS owns them would have every later blueprint writing `--cms-primary` in a
 * package that has nothing to do with a CMS.
 *
 * `.cms-*` **class** names are untouched and stay in `seef/cms-panel`: they are that
 * package's component anatomy, and `cms` is still the true word for them.
 *
 * This file is served **last**, after the kernel's own `site/_tokens.css` floor and after
 * every contributed directory, so it wins with no `@layer` and no specificity games. The
 * shell then overrides the brand-derived values inline on `<html style="…">`, which is what
 * makes a colour change live on the next request.
 *
 * The comments below are the design's own reasoning, carried over with the values they
 * explain. Design source: `design/cms-public-site-canvas/`, artboard 01 (token sheet).
 */

:root {
    /*
     * Client roles — the shell overrides these inline from the active Theme record, so what is
     * written here is the fallback an unconfigured site renders with. The three derived from
     * the primary are the values `ThemeTokens` computes for the default primary; they are
     * duplicated rather than expressed as `oklch(from …)` for the reason that class documents.
     */
    --seef-core-primary: #1D4ED8;
    --seef-core-primary-hover: #163EB0;
    --seef-core-primary-text: #1341CB;
    --seef-core-on-primary: #FFFFFF;

    /*
     * Mixed here rather than in PHP because only the theme knows its own surface — the tint is
     * 10% of the brand over whatever this theme calls paper, and pairs with `--seef-core-primary-text`
     * only, never with muted ink.
     */
    --seef-core-primary-tint: color-mix(in srgb, var(--seef-core-primary) 10%, var(--seef-core-surface));

    /* Surfaces */
    --seef-core-page-bg: #FBFBFB;
    --seef-core-surface: #FFFFFF;
    --seef-core-surface-sunken: #F6F7F9;
    --seef-core-surface-inverse: #111827;
    --seef-core-surface-footer: var(--seef-core-surface-inverse);
    --seef-core-cta-surface: var(--seef-core-surface-inverse);

    /* Ink. #585D68 at 6.6:1 and #6B7079 at 5.0:1 against white — both measured, both AA. */
    --seef-core-text: #111827;
    --seef-core-text-muted: color-mix(in srgb, var(--seef-core-text) 70%, var(--seef-core-surface));
    --seef-core-text-placeholder: color-mix(in srgb, var(--seef-core-text) 62%, var(--seef-core-surface));
    --seef-core-text-on-inverse: #FFFFFF;
    --seef-core-text-on-cta: var(--seef-core-text-on-inverse);

    /* Line — non-text, so 3:1 is not required, but it stays above 1.4:1 on the surface. */
    --seef-core-line: #E5E7EB;
    --seef-core-line-strong: color-mix(in srgb, var(--seef-core-text) 28%, var(--seef-core-surface));
    --seef-core-hairline-width: 1px;
    --seef-core-card-border: var(--seef-core-hairline-width) solid var(--seef-core-line);
    --seef-core-header-border: var(--seef-core-hairline-width) solid var(--seef-core-line);
    --seef-core-btn-border: 1px solid transparent;

    /* Shape — three radii and a pill, replacing eight. */
    --seef-core-radius-control: 8px;
    --seef-core-radius-card: 12px;
    --seef-core-radius-media: 12px;
    --seef-core-radius-pill: 999px;

    /* Depth — overlays only: the nav dropdown, the mobile sidebar, the pop-over. */
    --seef-core-shadow-overlay: 0 8px 32px rgb(0 0 0 / 0.16);

    /* Rhythm — the 4px scale's s7 / s8 / s9 at 360 / 768 / 1280. */
    --seef-core-section-py: 96px;
    --seef-core-section-py-tablet: 64px;
    --seef-core-section-py-phone: 48px;
    --seef-core-container: 1152px;
    --seef-core-gutter: 32px;
    --seef-core-gutter-tablet: 24px;
    --seef-core-gutter-phone: 16px;
    --seef-core-block-gap: 64px;
    --seef-core-prose-max: 68ch;

    /*
     * Type — one face, four weights. Letter-spacing is 0 everywhere: Arabic is a joined script
     * and negative tracking pulls the joins apart. Line-height is generous because Arabic
     * ascenders and descenders stack. Weight 600 appears exactly twice in the whole system —
     * the page title and button labels — and everything else earns hierarchy from size and
     * space. The two clamps interpolate between the drawn 360 and 1280 values.
     */
    --seef-core-font-body: 'IBM Plex Sans Arabic', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --seef-core-font-display: 'IBM Plex Sans Arabic', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --seef-core-font-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
    --seef-core-display-size: clamp(1.875rem, 1.4348rem + 1.9565vw, 3rem);
    --seef-core-h1-size: clamp(1.625rem, 1.3804rem + 1.087vw, 2.25rem);
    --seef-core-h1-weight: 600;
    /*
     * 1.4, not the 1.3 the token sheet writes.
     *
     * IBM Plex Sans Arabic's ink box is taller than 1.3 of its em: at the 26px the title takes
     * at 360, three lines measure 101px of line boxes and 104px of actual glyph, so the
     * headline overflows its own element and `PostDetailsEdgeCasesTest` reads it as clipped.
     * This is the design's own rule applied rather than contradicted — "line-height is
     * generous because Arabic ascenders and descenders stack" — the sheet simply carried a
     * value from the 36px case down to the 26px one, where it stops holding.
     */
    --seef-core-h1-leading: 1.4;
    --seef-core-h2-size: 1.5rem;
    --seef-core-h2-weight: 500;
    --seef-core-h2-leading: 1.35;
    --seef-core-h3-size: 1.25rem;
    --seef-core-h3-weight: 500;
    --seef-core-body-size: 1.0625rem;
    --seef-core-body-leading: 1.85;
    --seef-core-small-size: 0.9375rem;
    --seef-core-small-leading: 1.7;
    --seef-core-label-size: 0.75rem;
    --seef-core-label-weight: 500;
    --seef-core-label-tracking: 0.08em;

    /*
     * Motion — colour and border only. No transform, no lift, no bounce anywhere, so nothing
     * moves under a pointer and nothing is withheld from a screenshot.
     */
    --seef-core-transition: color 120ms linear, background-color 120ms linear, border-color 120ms linear;
    --seef-core-focus-ring: 2px solid var(--seef-core-primary-text);
    --seef-core-focus-offset: 2px;

    /*
     * The accent, its ink and the two ramps (feature 029, ADR-0004). Classic paints no
     * surface in the accent of its own accord — it is the quiet template, and the client's
     * colour stays confined to actions — but it declares every accent token all the same,
     * for the reason feature 017's contract test already enforces for the primary set: a
     * template renders correctly *before* any brand value applies, and a block that declares
     * only the tokens it happens to use leaves a shared component unpainted the day somebody
     * uses it here.
     *
     * The values are the ones `BrandTokens` computes for the default primary with no accent
     * set, so an unconfigured site and a configured one differ in the client's colours and
     * in nothing else.
     */
    --seef-core-accent: #A76416;
    --seef-core-accent-hover: #885010;
    --seef-core-accent-text: #824200;
    --seef-core-on-accent: #FFFFFF;

    --seef-core-primary-50: #ECF2FE;
    --seef-core-primary-700: #072BA0;
    --seef-core-primary-800: #011580;
    --seef-core-primary-900: #010062;
    --seef-core-accent-50: #F8F2ED;
    --seef-core-accent-200: #DFC3AB;
    --seef-core-accent-300: #D1AA88;

    /*
     * The brand-coloured dark surface and its ink (feature 029, T052, added with البوابة).
     * Classic paints no band in it — its dark surfaces are the neutral `surface-inverse`, and
     * that is the quiet template's whole character — but it declares the pair all the same,
     * for the reason every other token block does: a template that declares only what it
     * happens to use leaves a shared component unpainted the day somebody uses it here.
     */
    --seef-core-surface-brand: #1341CB;
    --seef-core-surface-brand-deep: #011283;
    --seef-core-on-surface-brand: #FFFFFF;
}

