/* ═══════════════════════════════════════════════════════════
   CŒUR ASTRAL - NUIT ÉDITORIALE COMPONENTS
   ═══════════════════════════════════════════════════════════

   Reusable .ca-* components of the redesign: buttons, fields, native
   controls, chips, segments, tabs, page header, cards, menu, empty state,
   notice, badges, avatar, skeleton, ornament, and the v2 look of the
   existing toast markup. Behaviour lives in js/v2/components.js.

   Loaded on every page, after base.css. Every selector starts with
   `.ui-v2 ` or `body.ui-v2`, so it outranks legacy element rules.
   Keyframes are prefixed `ca-`. Colours and sizes
   come from tokens.css.

   Legacy rules beaten here (each override says which one):
   - Materialize 1.0.0: button:focus { background-color: #2ab7a9 }, so every
     v2 button re-declares its background on :focus; [type=checkbox|radio]
     { position: absolute; opacity: 0; pointer-events: none } and
     select { display: none }, so v2 controls re-declare them; underlined
     inputs target :not(.browser-default), so every v2 input, select and
     textarea also carries class browser-default.
   - style.css:73-120 sets font, colour and margins on body, h1-h3, p, span,
     a, input, label; style.css:550 restyles input/textarea/select:focus. So
     components set font, colour and margin explicitly on what they style.
   - !important appears only twice: materialize-override.css:463-467 forces
     .toast background-color, border-radius and font-family, and
     materialize-override.css:489-492 forces h1-h6 to Montserrat 600, so
     Cormorant headings re-declare font-family and font-weight.

   Markup conventions: checkbox and radio text is a sibling <label for>,
   never input + span (Materialize decorates that). Control glyphs are
   backgrounds, never ::before/::after on <input>. {% icon %} takes no
   class, so an icon CSS must reach sits in a classed <span> wrapper. */

/* ─────────────────────────────────────────────────────────────
   BUTTON - .ca-btn plus at most one variant
   Variants only change the --ca-btn-* properties, so hover, :focus and the
   disabled state compose without re-declaring colours.
   Sizes: default M 48px, --l 52px, --s 44px (40px with a fine pointer).
   --premium needs a crown or sparkle-fill icon; --icon needs aria-label.
   Busy: aria-busy="true" plus aria-disabled="true", so assistive technology
   hears that the button is unavailable; components.js cancels its clicks
   (keyboard included) and it keeps its variant colours under the spinner.
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-btn {
  --ca-btn-h: 48px;
  --ca-btn-px: 28px;
  --ca-btn-fs: var(--fs-button);
  --ca-btn-bg: transparent;
  --ca-btn-fg: var(--ivory-100);
  --ca-btn-border: transparent;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-8);
  box-sizing: border-box;
  height: var(--ca-btn-h);
  padding: 0 var(--ca-btn-px);
  margin: 0;
  border: 1px solid var(--ca-btn-border);
  border-radius: var(--r-pill);
  background-color: var(--ca-btn-bg);
  color: var(--ca-btn-fg);
  font: 600 var(--ca-btn-fs)/var(--lh-button) var(--font-ui);
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
  vertical-align: middle;
  cursor: pointer;
  transition:
    background-color var(--dur-1) var(--ease-out),
    border-color var(--dur-1) var(--ease-out),
    color var(--dur-1) var(--ease-out),
    filter var(--dur-1) var(--ease-out);
}

/* Beats Materialize button:focus { background-color: #2ab7a9 }. */
.ui-v2 .ca-btn:focus {
  background-color: var(--ca-btn-bg);
}

.ui-v2 .ca-btn:focus-visible {
  outline: 2px solid var(--violet-300);
  outline-offset: 3px;
}

/* Inner spans keep the button type over style.css p, span { 1rem/1.5 }.
   :where() keeps this at class weight, so a badge or avatar nested in a
   button still wins with its own rule further down. */
.ui-v2 .ca-btn :where(span) {
  font: inherit;
  color: inherit;
}

.ui-v2 .ca-btn--primary {
  background-image: var(--gradient-brand);
  box-shadow: var(--gradient-brand-edge);
}

.ui-v2 .ca-btn--primary:hover {
  filter: brightness(1.1);
}

.ui-v2 .ca-btn--romance {
  --ca-btn-bg: var(--rose-600);
  --ca-btn-fg: var(--on-accent);
}

.ui-v2 .ca-btn--romance:hover {
  --ca-btn-bg: var(--rose-700);
}

.ui-v2 .ca-btn--premium {
  --ca-btn-bg: var(--gold-500);
  --ca-btn-fg: var(--night-900);
}

.ui-v2 .ca-btn--premium:hover {
  --ca-btn-bg: var(--gold-300);
}

.ui-v2 .ca-btn--premium:active {
  --ca-btn-bg: var(--gold-600);
}

.ui-v2 .ca-btn--secondary {
  --ca-btn-border: var(--line-strong);
}

.ui-v2 .ca-btn--secondary:hover {
  --ca-btn-bg: var(--wash-hover);
  --ca-btn-border: var(--ivory-300);
}

.ui-v2 .ca-btn--gold-outline {
  --ca-btn-border: var(--gold-400);
  --ca-btn-fg: var(--gold-400);
}

.ui-v2 .ca-btn--gold-outline:hover {
  --ca-btn-bg: var(--gold-wash);
}

/* Spec « text » variant: a 44px hit area around an underlined label. */
.ui-v2 .ca-btn--ghost {
  --ca-btn-h: 44px;
  --ca-btn-px: 4px;
  border: 0;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--underline-gold);
  text-underline-offset: 4px;
}

.ui-v2 .ca-btn--ghost:hover {
  --ca-btn-fg: var(--gold-400);
  text-decoration-color: var(--gold-400);
}

.ui-v2 .ca-btn--danger-outline {
  --ca-btn-border: var(--danger-line);
  --ca-btn-fg: var(--danger-text);
}

.ui-v2 .ca-btn--danger-outline:hover {
  --ca-btn-bg: var(--wash-hover);
}

/* Danger fill: irreversible confirmations only. */
.ui-v2 .ca-btn--danger {
  --ca-btn-bg: var(--danger-fill);
  --ca-btn-fg: var(--on-accent);
}

.ui-v2 .ca-btn--danger:hover {
  filter: brightness(1.1);
}

.ui-v2 .ca-btn--icon {
  --ca-btn-h: 44px;
  --ca-btn-px: 0;
  --ca-btn-border: var(--rule-chip);
  --ca-btn-fg: var(--ivory-300);
  width: 44px;
  padding: 0;
}

.ui-v2 .ca-btn--icon:hover {
  --ca-btn-bg: var(--surface-3);
  --ca-btn-fg: var(--ivory-100);
  --ca-btn-border: var(--rule-chip-hover);
}

.ui-v2 .ca-btn--l {
  --ca-btn-h: 52px;
  --ca-btn-px: 32px;
  --ca-btn-fs: var(--fs-button-lg);
}

.ui-v2 .ca-btn--s {
  --ca-btn-h: 44px;
  --ca-btn-px: 20px;
  --ca-btn-fs: 14px;
}

/* A mouse needs no 44px touch target. */
@media (pointer: fine) {
  .ui-v2 .ca-btn--s {
    --ca-btn-h: 40px;
  }
}

.ui-v2 .ca-btn--block {
  display: flex;
  width: 100%;
}

/* After the variants so hover, :active and :focus never repaint it. A busy
   button also carries aria-disabled but keeps its variant under the spinner. */
.ui-v2 .ca-btn:disabled,
.ui-v2 .ca-btn[aria-disabled="true"]:not([aria-busy="true"]) {
  --ca-btn-bg: var(--surface-3);
  --ca-btn-fg: var(--ivory-700);
  --ca-btn-border: transparent;
  background-image: none;
  box-shadow: none;
  filter: none;
  cursor: not-allowed;
}

.ui-v2 .ca-btn--ghost:disabled,
.ui-v2 .ca-btn--ghost[aria-disabled="true"] {
  --ca-btn-bg: transparent;
}

/* Busy: the label goes transparent (it keeps the width) under a spinner
   drawn in the variant's text colour. pointer-events stops the mouse only;
   components.js also cancels keyboard clicks. */
.ui-v2 .ca-btn[aria-busy="true"] {
  color: transparent;
  pointer-events: none;
}

.ui-v2 .ca-btn[aria-busy="true"]::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  box-sizing: border-box;
  width: 16px;
  height: 16px;
  margin: -8px 0 0 -8px;
  border: 2px solid var(--ca-btn-fg);
  border-top-color: transparent;
  border-radius: 50%;
  animation: ca-btn-spin var(--dur-spin) linear infinite;
}

@keyframes ca-btn-spin {
  to {
    transform: rotate(360deg);
  }
}

/* ─────────────────────────────────────────────────────────────
   FIELD - label, box, control, help, error, counter
   Markup: .ca-field > label.ca-field__label + .ca-field__box (with
   --trailing when an icon or button sits at the right) > control
   (input/select/textarea.ca-field__control.browser-default), then
   .ca-field__help / .ca-field__error (aria-describedby) / .ca-field__counter.
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-8);
  margin: 0;
}

/* padding: 0 beats style.css legend { padding: 0 .7rem } when the label is
   a radio group's <legend>, so it aligns with the controls below. */
.ui-v2 .ca-field__label {
  display: block;
  margin: 0;
  padding: 0;
  color: var(--ivory-300);
  font: 600 var(--fs-label)/var(--lh-label) var(--font-ui);
}

.ui-v2 .ca-field__box {
  position: relative;
}

/* Beats style.css select (2px border, 10px radius) and Materialize
   select { display: none } through specificity and an explicit display. */
.ui-v2 .ca-field__control {
  display: block;
  width: 100%;
  box-sizing: border-box;
  height: 48px;
  padding: 0 var(--sp-16);
  margin: 0;
  border: 1px solid var(--ivory-700);
  border-radius: var(--r-md);
  background-color: var(--surface-2);
  color: var(--ivory-100);
  font: 400 16px/24px var(--font-ui);
  color-scheme: dark;
  -webkit-appearance: none;
  appearance: none;
  transition:
    border-color var(--dur-1) var(--ease-out),
    box-shadow var(--dur-1) var(--ease-out);
}

.ui-v2 .ca-field__control::placeholder {
  color: var(--ivory-500);
  opacity: 1;
}

.ui-v2 .ca-field__control:hover {
  border-color: var(--line-strong);
}

/* Beats style.css:550 input:focus (2px #873aac border, light background). */
.ui-v2 .ca-field__control:focus {
  outline: none;
  border-color: var(--violet-400);
  box-shadow: 0 0 0 3px var(--field-ring);
  background-color: var(--surface-2);
}

.ui-v2 select.ca-field__control {
  padding-right: 44px;
  cursor: pointer;
}

.ui-v2 textarea.ca-field__control {
  height: auto;
  min-height: 132px;
  padding: var(--sp-12) var(--sp-16);
  resize: vertical;
}

/* Room for the chevron, status icon or reveal button at every width. */
.ui-v2 .ca-field__box--trailing .ca-field__control {
  padding-right: 44px;
}

.ui-v2 .ca-field__control:disabled {
  border-style: dashed;
  border-color: var(--ivory-700);
  background-color: var(--surface-1);
  color: var(--ivory-500);
  -webkit-text-fill-color: var(--ivory-500);
  opacity: 1;
  cursor: not-allowed;
}

/* After :focus, so an invalid field keeps its red border while focused. */
.ui-v2 .ca-field--error .ca-field__control,
.ui-v2 .ca-field__control[aria-invalid="true"] {
  border-color: var(--danger-line);
}

/* The border no longer changes on focus here, and the translucent
   --field-ring alone is about 1.9:1: a violet-300 ring over a night gap,
   as on the range thumb, keeps the focus indicator above 3:1. */
.ui-v2 .ca-field--error .ca-field__control:focus,
.ui-v2 .ca-field__control[aria-invalid="true"]:focus {
  box-shadow: 0 0 0 2px var(--night-900), 0 0 0 4px var(--violet-300);
}

.ui-v2 .ca-field__chevron,
.ui-v2 .ca-field__status {
  position: absolute;
  top: 14px;
  right: 14px;
  line-height: 0;
  pointer-events: none;
}

.ui-v2 .ca-field__chevron {
  display: inline-flex;
  color: var(--ivory-500);
}

/* Rendered always, shown only once the field is valid. */
.ui-v2 .ca-field__status {
  display: none;
  color: var(--success);
}

.ui-v2 .ca-field--valid .ca-field__status {
  display: inline-flex;
}

.ui-v2 .ca-field__toggle {
  position: absolute;
  top: 2px;
  right: 2px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  margin: 0;
  border: 0;
  border-radius: var(--r-md);
  background-color: transparent;
  color: var(--ivory-500);
  cursor: pointer;
}

/* Beats Materialize button:focus { background-color: #2ab7a9 }. */
.ui-v2 .ca-field__toggle:focus {
  background-color: transparent;
}

.ui-v2 .ca-field__toggle:hover {
  color: var(--ivory-100);
}

.ui-v2 .ca-field__toggle-show,
.ui-v2 .ca-field__toggle-hide {
  display: inline-flex;
  line-height: 0;
}

.ui-v2 .ca-field__toggle-hide,
.ui-v2 .ca-field__toggle[aria-pressed="true"] .ca-field__toggle-show {
  display: none;
}

.ui-v2 .ca-field__toggle[aria-pressed="true"] .ca-field__toggle-hide {
  display: inline-flex;
}

.ui-v2 .ca-field__help {
  margin: 0;
  color: var(--ivory-500);
  font: 400 13px/20px var(--font-ui);
}

/* Django help text as a list; beats Materialize ul:not(.browser-default). */
.ui-v2 ul.ca-field__help {
  padding-left: 18px;
}

.ui-v2 ul.ca-field__help li {
  list-style-type: disc;
}

.ui-v2 .ca-field__error {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin: 0;
  color: var(--danger-text);
  font: 500 13px/20px var(--font-ui);
}

/* The 16px alert icon centred on the first 20px line. */
.ui-v2 .ca-field__error .ca-icon {
  margin-top: 2px;
}

.ui-v2 .ca-field__counter {
  margin: 0;
  color: var(--ivory-500);
  font: 500 var(--fs-caption)/var(--lh-caption) var(--font-ui);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* ─────────────────────────────────────────────────────────────
   CHECKBOX & RADIO - native inputs, sibling <label for>
   Re-declares position, opacity, pointer-events and display to beat
   Materialize [type=checkbox|radio] { position: absolute; opacity: 0;
   pointer-events: none }. The check mark is a data-URI SVG whose stroke
   is --ivory-100 (#F4EFE6): custom properties cannot reach a data URI.
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-check,
.ui-v2 .ca-radio {
  display: flex;
  align-items: center;
  gap: var(--sp-12);
  min-height: 44px;
}

.ui-v2 input.ca-check__input,
.ui-v2 input.ca-radio__input {
  position: static;
  opacity: 1;
  pointer-events: auto;
  display: inline-block;
  -webkit-appearance: none;
  appearance: none;
  flex: none;
  box-sizing: border-box;
  width: 22px;
  height: 22px;
  margin: 0;
  border: 1.5px solid var(--line-strong);
  background-color: var(--surface-1);
  background-position: center;
  background-repeat: no-repeat;
  color-scheme: dark;
  cursor: pointer;
}

.ui-v2 input.ca-check__input {
  border-radius: var(--r-sm);
}

.ui-v2 input.ca-radio__input {
  border-radius: 50%;
}

.ui-v2 input.ca-check__input:checked {
  border-color: var(--violet-500);
  background-color: var(--violet-500);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23F4EFE6' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12l5 5l10 -10'/%3E%3C/svg%3E");
  background-size: 16px 16px;
}

/* 10px dot. */
.ui-v2 input.ca-radio__input:checked {
  border-color: var(--violet-500);
  background-image: radial-gradient(circle, var(--violet-500) 0 5px, transparent 5.5px);
}

.ui-v2 input.ca-check__input:disabled,
.ui-v2 input.ca-radio__input:disabled {
  border-color: var(--ivory-700);
  cursor: not-allowed;
}

.ui-v2 .ca-check__label,
.ui-v2 .ca-radio__label {
  margin: 0;
  color: var(--ivory-300);
  font: 400 var(--fs-body-small)/var(--lh-body-small) var(--font-ui);
  cursor: pointer;
}

.ui-v2 input.ca-check__input:disabled + .ca-check__label,
.ui-v2 input.ca-radio__input:disabled + .ca-radio__label {
  color: var(--ivory-500);
  cursor: not-allowed;
}

/* Links in a label keep the label size over style.css a { 1rem/1.2 }. */
.ui-v2 .ca-check__label a,
.ui-v2 .ca-radio__label a {
  font: inherit;
}

/* ─────────────────────────────────────────────────────────────
   SWITCH - input[type=checkbox][role=switch].ca-switch
   Track 44×26; the 20px thumb is a radial gradient, so it moves without
   any pseudo-element on <input>. Same Materialize re-declarations as the
   checkbox.
   ───────────────────────────────────────────────────────────── */
.ui-v2 input.ca-switch {
  position: static;
  opacity: 1;
  pointer-events: auto;
  display: inline-block;
  -webkit-appearance: none;
  appearance: none;
  flex: none;
  box-sizing: border-box;
  width: 44px;
  height: 26px;
  margin: 0;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-pill);
  background-color: var(--surface-4);
  background-image: radial-gradient(circle at 12px 50%, var(--ivory-100) 0 10px, transparent 10.5px);
  color-scheme: dark;
  cursor: pointer;
  transition:
    background-color var(--dur-1) var(--ease-out),
    border-color var(--dur-1) var(--ease-out);
}

.ui-v2 input.ca-switch:checked {
  border-color: var(--violet-600);
  background-color: var(--violet-600);
  background-image: radial-gradient(circle at calc(100% - 12px) 50%, var(--ivory-100) 0 10px, transparent 10.5px);
}

.ui-v2 input.ca-switch:disabled {
  border-color: var(--ivory-700);
  cursor: not-allowed;
}

.ui-v2 .ca-switch-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-16);
  min-height: 44px;
  border-top: 1px solid var(--rule-soft);
}

.ui-v2 .ca-switch-row:last-child {
  border-bottom: 1px solid var(--rule-soft);
}

.ui-v2 .ca-switch-row > label {
  margin: 0;
  color: var(--ivory-300);
  font: 500 var(--fs-body-small)/var(--lh-body-small) var(--font-ui);
  cursor: pointer;
}

/* ─────────────────────────────────────────────────────────────
   RANGE - .ca-range[data-ca-range][data-format]
   The native track is transparent; .ca-range__track::before draws the 4px
   line and its fill from --ca-range-from / --ca-range-to, which
   components.js sets on the root. The line is inset by the thumb radius
   (10px), so a percentage lands under the thumb centre. --dual stacks two
   inputs whose thumbs alone take the pointer; when both meet in the upper
   half, components.js sets data-ca-range-top="low" and the low one goes
   on top, as the later input would otherwise always win.
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-range__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-8);
}

.ui-v2 .ca-range__output {
  color: var(--ivory-100);
  font: 600 var(--fs-body-small)/20px var(--font-ui);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.ui-v2 .ca-range__track {
  position: relative;
  height: 44px;
}

.ui-v2 .ca-range__track::before {
  content: "";
  position: absolute;
  top: 50%;
  right: 10px;
  left: 10px;
  height: 4px;
  margin-top: -2px;
  border-radius: var(--r-pill);
  background-image: linear-gradient(
    to right,
    var(--ivory-700) var(--ca-range-from, 0%),
    var(--violet-400) var(--ca-range-from, 0%),
    var(--violet-400) var(--ca-range-to, 0%),
    var(--ivory-700) var(--ca-range-to, 0%)
  );
  pointer-events: none;
}

/* Beats Materialize input[type=range] (margin 15px 0, teal track and
   thumb). Positioned so it paints above the track line. */
.ui-v2 input.ca-range__input {
  position: relative;
  display: block;
  -webkit-appearance: none;
  appearance: none;
  box-sizing: border-box;
  width: 100%;
  height: 44px;
  padding: 0;
  margin: 0;
  border: 0;
  background: transparent;
  color-scheme: dark;
  cursor: pointer;
}

/* The ring is drawn on the thumb below. */
.ui-v2 input.ca-range__input:focus-visible {
  outline: none;
}

.ui-v2 input.ca-range__input::-webkit-slider-runnable-track {
  height: 4px;
  border: 0;
  background: transparent;
}

.ui-v2 input.ca-range__input::-moz-range-track {
  height: 4px;
  border: 0;
  background: transparent;
}

.ui-v2 input.ca-range__input::-moz-range-progress {
  background: transparent;
}

/* margin-top centres the 20px thumb on the 4px WebKit track. */
.ui-v2 input.ca-range__input::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  box-sizing: border-box;
  width: 20px;
  height: 20px;
  margin-top: -8px;
  border: 0;
  border-radius: 50%;
  background: var(--ivory-100);
  box-shadow: var(--shadow-thumb);
  cursor: grab;
}

.ui-v2 input.ca-range__input::-moz-range-thumb {
  box-sizing: border-box;
  width: 20px;
  height: 20px;
  border: 0;
  border-radius: 50%;
  background: var(--ivory-100);
  box-shadow: var(--shadow-thumb);
  cursor: grab;
}

.ui-v2 input.ca-range__input:active::-webkit-slider-thumb {
  cursor: grabbing;
}

.ui-v2 input.ca-range__input:active::-moz-range-thumb {
  cursor: grabbing;
}

/* 2px ring 2px off the thumb. body.ui-v2 .ca-range outranks Materialize
   .keyboard-focused input[type=range]:focus:not(.active)::-webkit-slider-thumb. */
body.ui-v2 .ca-range input.ca-range__input:focus-visible::-webkit-slider-thumb {
  box-shadow: 0 0 0 2px var(--night-900), 0 0 0 4px var(--violet-300);
}

body.ui-v2 .ca-range input.ca-range__input:focus-visible::-moz-range-thumb {
  box-shadow: 0 0 0 2px var(--night-900), 0 0 0 4px var(--violet-300);
}

.ui-v2 .ca-range--dual input.ca-range__input {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.ui-v2 .ca-range--dual input.ca-range__input::-webkit-slider-thumb {
  pointer-events: auto;
}

.ui-v2 .ca-range--dual input.ca-range__input::-moz-range-thumb {
  pointer-events: auto;
}

/* isolation keeps the raised input's z-index inside the track. */
.ui-v2 .ca-range--dual .ca-range__track {
  isolation: isolate;
}

.ui-v2 .ca-range--dual[data-ca-range-top="low"] input.ca-range__input:first-of-type {
  z-index: 1;
}

/* ─────────────────────────────────────────────────────────────
   CHIP - button[aria-pressed] (data-ca-toggle flips it) or
   input.ca-chip__input + label.ca-chip
   44px tall (40px with a fine pointer). Pressed: violet tint, the
   span.ca-chip__check shows and span.ca-chip__icon hides. The label sits
   in span.ca-chip__text, so a long name or translation ends in an ellipsis
   instead of crossing the pill.
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  box-sizing: border-box;
  height: 44px;
  padding: 0 var(--sp-16);
  margin: 0;
  border: 1px solid var(--rule-chip);
  border-radius: var(--r-pill);
  background-color: transparent;
  color: var(--ivory-300);
  font: 500 var(--fs-body-small)/20px var(--font-ui);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color var(--dur-1) var(--ease-out),
    border-color var(--dur-1) var(--ease-out),
    color var(--dur-1) var(--ease-out);
}

@media (pointer: fine) {
  .ui-v2 .ca-chip {
    height: 40px;
  }
}

/* Beats Materialize button:focus { background-color: #2ab7a9 }. */
.ui-v2 .ca-chip:focus {
  background-color: transparent;
}

.ui-v2 .ca-chip:hover {
  border-color: var(--rule-chip-hover);
}

.ui-v2 .ca-chip[aria-pressed="true"],
.ui-v2 .ca-chip__input:checked + .ca-chip {
  border-color: var(--violet-500);
  background-color: var(--violet-tint);
  color: var(--ivory-100);
}

.ui-v2 .ca-chip__check,
.ui-v2 .ca-chip__icon {
  display: inline-flex;
  flex: none;
  line-height: 0;
}

.ui-v2 .ca-chip__text {
  min-width: 0;
  overflow: hidden;
  font: inherit;
  color: inherit;
  text-overflow: ellipsis;
}

.ui-v2 .ca-chip__check,
.ui-v2 .ca-chip[aria-pressed="true"] .ca-chip__icon,
.ui-v2 .ca-chip__input:checked + .ca-chip .ca-chip__icon {
  display: none;
}

.ui-v2 .ca-chip[aria-pressed="true"] .ca-chip__check,
.ui-v2 .ca-chip__input:checked + .ca-chip .ca-chip__check {
  display: inline-flex;
}

/* Visually hidden, still focusable; its label draws the focus ring. */
.ui-v2 .ca-chip__input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
  opacity: 0;
}

.ui-v2 .ca-chip__input:focus-visible + .ca-chip {
  outline: 2px solid var(--violet-300);
  outline-offset: 2px;
}

.ui-v2 .ca-chip--sign {
  justify-content: flex-start;
}

/* Numerology: a 44px circle with a Cormorant numeral at every pointer. */
.ui-v2 .ca-chip--number {
  width: 44px;
  height: 44px;
  padding: 0;
  font: 600 20px/1 var(--font-display);
  font-variant-numeric: lining-nums;
}

/* A selected value with a remove button, e.g. « France ». */
.ui-v2 .ca-chip--removable {
  padding-right: var(--sp-4);
  border-color: var(--violet-500);
  background-color: var(--violet-tint);
  color: var(--ivory-100);
  cursor: default;
}

.ui-v2 .ca-chip--removable .ca-chip__check {
  display: inline-flex;
  color: var(--violet-300);
}

.ui-v2 .ca-chip__remove {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 32px;
  height: 32px;
  padding: 0;
  margin: 0;
  border: 0;
  border-radius: 50%;
  background-color: transparent;
  color: var(--ivory-500);
  cursor: pointer;
}

/* Beats Materialize button:focus { background-color: #2ab7a9 }. */
.ui-v2 .ca-chip__remove:focus {
  background-color: transparent;
}

.ui-v2 .ca-chip__remove:hover {
  color: var(--ivory-100);
}

/* 32px drawn, 44px hit area. */
.ui-v2 .ca-chip__remove::after {
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: 50%;
}

/* Spec A asks for a « grille de 3 », but « Capricorne » needs about 141px
   with the 16px padding and 18px icon: columns stay at least 9rem wide and
   drop to two (390 phone) or one (248px Recherche sidebar) rather than
   overflow. */
.ui-v2 .ca-chip-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 9rem), 1fr));
  gap: var(--sp-8);
}

.ui-v2 .ca-chip-grid .ca-chip {
  min-width: 0;
}

/* ─────────────────────────────────────────────────────────────
   SEGMENTED - .ca-segmented[role=radiogroup] of
   input.ca-segmented__input + label.ca-segmented__option
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-segmented {
  position: relative;
  display: flex;
  gap: var(--sp-4);
  box-sizing: border-box;
  height: 44px;
  padding: 3px;
  margin: 0;
  border: 1px solid var(--rule-chip);
  border-radius: var(--r-pill);
}

.ui-v2 .ca-segmented__input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
  opacity: 0;
}

.ui-v2 .ca-segmented__option {
  display: flex;
  flex: 1 1 0;
  align-items: center;
  justify-content: center;
  min-width: 0;
  box-sizing: border-box;
  height: 100%;
  padding: 0 var(--sp-12);
  margin: 0;
  border-radius: var(--r-pill);
  color: var(--ivory-300);
  font: 500 var(--fs-body-small)/20px var(--font-ui);
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color var(--dur-1) var(--ease-out),
    color var(--dur-1) var(--ease-out);
}

.ui-v2 .ca-segmented__option:hover {
  color: var(--ivory-100);
}

.ui-v2 .ca-segmented__input:checked + .ca-segmented__option {
  background-color: var(--violet-tint);
  box-shadow: inset 0 0 0 1px var(--violet-500);
  color: var(--ivory-100);
}

.ui-v2 .ca-segmented__input:focus-visible + .ca-segmented__option {
  outline: 2px solid var(--violet-300);
  outline-offset: 2px;
}

/* ─────────────────────────────────────────────────────────────
   TABS - underlined, sentence case
   [role=tablist] of button.ca-tabs__tab[role=tab][aria-selected]
   [aria-controls] (keyboard in components.js), or a <nav> of
   a.ca-tabs__tab[aria-current=page] that changes page.
   The container scrolls sideways and so clips its overflow: a 4px padding,
   cancelled by a negative margin, keeps the focus ring visible, and the
   1px rule is a background line on the content box, under the 2px bar.
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-tabs {
  display: flex;
  gap: 28px;
  margin: -4px;
  padding: 4px;
  list-style: none;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
  background-image: linear-gradient(var(--rule-soft), var(--rule-soft));
  background-origin: content-box;
  background-clip: content-box;
  background-position: left bottom;
  background-size: 100% 1px;
  background-repeat: no-repeat;
}

.ui-v2 .ca-tabs::-webkit-scrollbar {
  display: none;
}

/* Phones: fade the right edge so an overflowing list reads as scrollable.
   The mask uses black for opacity only. Once the strip is scrolled away
   from its start (.ca-tabs--scrolled, components.js), the left edge fades
   too, so tabs hidden on the left read as reachable (ALS-1190). */
@media (max-width: 599.98px) {
  .ui-v2 .ca-tabs {
    -webkit-mask-image: linear-gradient(to right, black calc(100% - 32px), transparent);
    mask-image: linear-gradient(to right, black calc(100% - 32px), transparent);
  }

  .ui-v2 .ca-tabs.ca-tabs--scrolled {
    -webkit-mask-image: linear-gradient(to right, transparent, black 32px, black calc(100% - 32px), transparent);
    mask-image: linear-gradient(to right, transparent, black 32px, black calc(100% - 32px), transparent);
  }
}

.ui-v2 .ca-tabs__tab {
  position: relative;
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 6px;
  height: 48px;
  padding: 0;
  margin: 0;
  border: 0;
  background-color: transparent;
  color: var(--ivory-500);
  /* Spec « Onglets soulignés »: 14/20 at every width, unlike the nav links
     (--fs-nav grows to 15px from 1280px). */
  font: 600 var(--fs-body-small)/20px var(--font-ui);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

/* Beats Materialize button:focus { background-color: #2ab7a9 }. */
.ui-v2 .ca-tabs__tab:focus {
  background-color: transparent;
}

.ui-v2 .ca-tabs__tab:hover,
.ui-v2 .ca-tabs__tab[aria-selected="true"],
.ui-v2 .ca-tabs__tab[aria-current="page"] {
  color: var(--ivory-100);
}

.ui-v2 .ca-tabs__tab[aria-selected="true"]::after,
.ui-v2 .ca-tabs__tab[aria-current="page"]::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 2px;
  border-radius: 2px;
  background-color: var(--violet-400);
}

.ui-v2 .ca-tabs__count {
  color: inherit;
  font: inherit;
  font-variant-numeric: tabular-nums;
}

/* ─────────────────────────────────────────────────────────────
   PAGE HEADER « La une » - left-aligned eyebrow, H1, lede, gold rule,
   actions on the right
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-page-header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-24);
}

.ui-v2 .ca-page-header__text {
  min-width: 0;
}

/* Beats style.css h1 { margin-bottom: 6rem }. */
.ui-v2 .ca-page-header__title {
  max-width: 18ch;
  margin: var(--sp-12) 0 0;
  text-wrap: balance;
}

.ui-v2 .ca-page-header__lede {
  margin: var(--sp-16) 0 0;
}

/* A live count inside the lede (Recherche) or inside a tab counter (Mes
   harmonies) keeps its parent's type over style.css p, span { 1rem/1.5 };
   :where() keeps this at class weight, as .ca-btn :where(span) does. */
.ui-v2 .ca-page-header__lede :where(span),
.ui-v2 .ca-tabs__count :where(span) {
  font: inherit;
  color: inherit;
}

.ui-v2 .ca-page-header__rule {
  display: block;
  width: 64px;
  height: 1px;
  margin-top: var(--sp-32);
  background-color: var(--underline-gold);
}

.ui-v2 .ca-page-header__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-12);
}

/* ─────────────────────────────────────────────────────────────
   CARD - tonal levels 1 and 2, editorial gold frame
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-card {
  box-sizing: border-box;
  padding: var(--card-pad);
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  background-color: var(--surface-1);
}

.ui-v2 .ca-card--raised {
  background-color: var(--surface-2);
  box-shadow: var(--shadow-menu);
}

.ui-v2 .ca-card--gold {
  padding: 40px;
  border-color: var(--frame-gold);
  border-radius: var(--r-lg);
}

@media (max-width: 599.98px) {
  .ui-v2 .ca-card--gold {
    padding: var(--sp-24);
  }
}

/* ─────────────────────────────────────────────────────────────
   ACCOUNT MENU - 300px popover of 44px rows
   Styles only: placement and keyboard land with the shell lot.
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-menu {
  box-sizing: border-box;
  width: 300px;
  max-width: 100%;
  padding: var(--sp-8);
  margin: 0;
  list-style: none;
  border: 1px solid var(--rule-dialog);
  border-radius: var(--r-md);
  background-color: var(--surface-2);
  box-shadow: var(--shadow-menu);
  z-index: var(--layer-menu);
}

.ui-v2 .ca-menu__header {
  display: flex;
  align-items: center;
  gap: var(--sp-12);
  padding: var(--sp-8) var(--sp-12) var(--sp-12);
}

/* Cormorant first name; !important beats materialize-override.css h1-h6
   when the name is a heading. */
.ui-v2 .ca-menu__name {
  margin: 0;
  color: var(--ivory-100);
  font-family: var(--font-display) !important;
  font-weight: 600 !important;
  font-size: 22px;
  line-height: 26px;
}

.ui-v2 .ca-menu__item {
  display: flex;
  align-items: center;
  gap: var(--sp-12);
  box-sizing: border-box;
  width: 100%;
  min-height: 44px;
  padding: 0 var(--sp-12);
  margin: 0;
  border: 0;
  border-radius: var(--r-sm);
  background-color: transparent;
  color: var(--ivory-100);
  font: 500 var(--fs-body-small)/20px var(--font-ui);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

/* Beats Materialize button:focus { background-color: #2ab7a9 }. */
.ui-v2 .ca-menu__item:focus {
  background-color: transparent;
}

.ui-v2 .ca-menu__item:hover,
.ui-v2 .ca-menu__item:focus-visible {
  background-color: var(--surface-3);
}

.ui-v2 .ca-menu__item .ca-icon {
  color: var(--ivory-500);
}

.ui-v2 .ca-menu__item--danger,
.ui-v2 .ca-menu__item--danger .ca-icon {
  color: var(--danger-text);
}

.ui-v2 .ca-menu__item--premium .ca-icon {
  color: var(--gold-400);
}

.ui-v2 .ca-menu__meta {
  margin-left: auto;
  color: var(--ivory-500);
  font: 600 var(--fs-caption)/var(--lh-caption) var(--font-ui);
}

.ui-v2 .ca-menu__sep {
  height: 1px;
  padding: 0;
  margin: var(--sp-8) 0;
  border: 0;
  background-color: var(--rule-soft);
}

/* ─────────────────────────────────────────────────────────────
   EMPTY STATE - constellation art, Cormorant title, one CTA
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 420px;
  padding: var(--sp-64) 0;
  margin: 0 auto;
  text-align: center;
}

.ui-v2 .ca-empty__art {
  display: block;
  width: 200px;
  height: 120px;
  color: var(--gold-400);
}

/* !important beats materialize-override.css h1-h6 Montserrat 600. */
.ui-v2 .ca-empty__title {
  margin: var(--sp-16) 0 var(--sp-8);
  color: var(--ivory-100);
  font-family: var(--font-display) !important;
  font-weight: 500 !important;
  font-size: 28px;
  line-height: 34px;
}

.ui-v2 .ca-empty__text {
  margin: 0 0 var(--sp-24);
  color: var(--ivory-300);
  font: 400 15px/24px var(--font-ui);
}

/* ─────────────────────────────────────────────────────────────
   NOTICE - framed message; the icon colour carries the tone, never a
   coloured left border
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-notice {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr);
  align-items: start;
  gap: var(--sp-16);
  box-sizing: border-box;
  padding: var(--sp-20) var(--sp-24);
  margin: 0;
  border: 1px solid var(--rule);
  border-radius: var(--r-md);
  background-color: var(--surface-1);
}

.ui-v2 .ca-notice__icon {
  display: inline-flex;
  line-height: 0;
  color: var(--gold-400);
}

.ui-v2 .ca-notice--info .ca-notice__icon {
  color: var(--gold-400);
}

.ui-v2 .ca-notice--success .ca-notice__icon {
  color: var(--success);
}

.ui-v2 .ca-notice--warning .ca-notice__icon {
  color: var(--warning);
}

.ui-v2 .ca-notice--danger .ca-notice__icon {
  color: var(--danger-text);
}

/* Montserrat 600 also when it is a heading, so no !important needed. */
.ui-v2 .ca-notice__title {
  margin: 0;
  color: var(--ivory-100);
  font: 600 15px/22px var(--font-ui);
}

.ui-v2 .ca-notice__text {
  margin: var(--sp-4) 0 0;
  color: var(--ivory-300);
  font: 400 var(--fs-body-small)/var(--lh-body-small) var(--font-ui);
}

.ui-v2 .ca-notice__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-12);
  margin-top: var(--sp-12);
}

/* ─────────────────────────────────────────────────────────────
   BADGE & ✦ PILL
   The server caps badge counts at « 99+ ». The pill keeps a 44px hit
   area through ::before; its icon wrapper is gold.
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--r-pill);
  background-color: var(--gold-400);
  box-shadow: 0 0 0 2px var(--night-900);
  color: var(--night-900);
  font: 600 var(--fs-badge)/var(--lh-badge) var(--font-ui);
  font-variant-numeric: tabular-nums;
}

.ui-v2 .ca-badge--dot {
  width: 8px;
  min-width: 0;
  height: 8px;
  padding: 0;
  background-color: var(--rose-500);
  box-shadow: none;
}

.ui-v2 .ca-stars-pill {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  box-sizing: border-box;
  height: 32px;
  padding: 0 var(--sp-12);
  margin: 0;
  border: 1px solid var(--ring-gold);
  border-radius: var(--r-pill);
  background-color: var(--gold-wash);
  color: var(--ivory-100);
  font: 600 13px/16px var(--font-ui);
  font-variant-numeric: tabular-nums;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

/* Beats Materialize button:focus { background-color: #2ab7a9 }. */
.ui-v2 .ca-stars-pill:focus {
  background-color: var(--gold-wash);
}

.ui-v2 .ca-stars-pill:hover {
  border-color: var(--gold-400);
}

.ui-v2 .ca-stars-pill::before {
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: var(--r-pill);
}

.ui-v2 .ca-stars-pill .ca-icon {
  color: var(--gold-400);
}

.ui-v2 .ca-stars-pill__count {
  min-width: 3ch;
  color: inherit;
  font: inherit;
}

/* Tablet and phone: 28px pill, still a 44px hit area. */
@media (max-width: 1023.98px) {
  .ui-v2 .ca-stars-pill {
    height: 28px;
  }

  .ui-v2 .ca-stars-pill::before {
    inset: -8px;
  }
}

/* ─────────────────────────────────────────────────────────────
   AVATAR - photo or monogram, 44px by default
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-avatar {
  --ca-avatar-size: 44px;
  position: relative;
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  width: var(--ca-avatar-size);
  height: var(--ca-avatar-size);
  border-radius: var(--r-pill);
  background-color: var(--surface-2);
  color: var(--ivory-100);
  font: 600 16px/1 var(--font-ui);
}

/* 12px monogram: the smallest text the spec allows. */
.ui-v2 .ca-avatar--24 {
  --ca-avatar-size: 24px;
  font-size: var(--fs-caption);
}

.ui-v2 .ca-avatar--36 {
  --ca-avatar-size: 36px;
}

.ui-v2 .ca-avatar--48 {
  --ca-avatar-size: 48px;
}

.ui-v2 .ca-avatar--ring {
  box-shadow: 0 0 0 1px var(--underline-gold);
}

/* No photo: Cormorant italic gold initial in a thin gold ring (Échanges
   mockup). Half the avatar, never under the 20px Cormorant floor. */
.ui-v2 .ca-avatar--monogram {
  box-shadow: inset 0 0 0 1px var(--rule-gold);
  color: var(--gold-400);
  font: italic 500 max(20px, calc(var(--ca-avatar-size) / 2))/1 var(--font-display);
}

/* 24px: too small for Cormorant, so the Montserrat caption initial. */
.ui-v2 .ca-avatar--24.ca-avatar--monogram {
  font: 600 var(--fs-caption)/1 var(--font-ui);
}

.ui-v2 .ca-avatar__img {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: var(--r-pill);
  object-fit: cover;
}

.ui-v2 .ca-avatar__status {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background-color: var(--online);
  box-shadow: 0 0 0 2px var(--night-900);
}

/* ─────────────────────────────────────────────────────────────
   SKELETON - one of the spec's three allowed loops; base.css stops it
   under reduced motion
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-skeleton {
  display: block;
  border-radius: var(--r-sm);
  background: var(--skeleton);
  background-size: var(--skeleton-size);
  animation: ca-skeleton var(--dur-loop) linear infinite;
}

.ui-v2 .ca-skeleton--text {
  height: 12px;
}

.ui-v2 .ca-skeleton--circle {
  border-radius: 50%;
}

@keyframes ca-skeleton {
  from {
    background-position: 100% 0;
  }

  to {
    background-position: -100% 0;
  }
}

/* ─────────────────────────────────────────────────────────────
   RULE ORNAMENT - two fading gold lines around a 12px sparkle-fill
   Markup: <div class="ca-rule-ornament" aria-hidden="true"><span></span>
   {% icon "sparkle-fill" size=12 %}<span></span></div>
   ───────────────────────────────────────────────────────────── */
.ui-v2 .ca-rule-ornament {
  display: flex;
  align-items: center;
  gap: var(--sp-16);
  color: var(--gold-400);
}

.ui-v2 .ca-rule-ornament > span:first-child,
.ui-v2 .ca-rule-ornament > span:last-child {
  flex: 1;
  height: 1px;
  background-image: linear-gradient(to right, transparent, var(--underline-gold));
}

.ui-v2 .ca-rule-ornament > span:last-child {
  background-image: linear-gradient(to left, transparent, var(--underline-gold));
}

/* ─────────────────────────────────────────────────────────────
   TOAST - v2 look of the toast-notification.js markup
   (.toast-container > .toast.toast-<type> > .toast-progress, .toast-icon,
   .toast-content > .toast-message + .toast-subtitle, .toast-close),
   toast.css and the script stay untouched.
   Toasts sit under the v2 header (--ca-header-height) at every width;
   grid [icon 20][text][close 44], no coloured left border. The three
   !important beat materialize-override.css:463-467.
   ───────────────────────────────────────────────────────────── */
.ui-v2 .toast-container {
  top: calc(var(--ca-header-height) + var(--sp-16));
  right: var(--sp-24);
  bottom: auto;
  left: auto;
  width: 360px;
  max-width: calc(100vw - 24px);
  flex-direction: column;
  gap: var(--sp-8);
}

@media (max-width: 599.98px) {
  .ui-v2 .toast-container {
    top: calc(var(--ca-header-height) + var(--sp-8));
    right: var(--sp-12);
    left: var(--sp-12);
    width: auto;
    max-width: none;
  }
}

/* Also overrides Materialize .toast (flex, 10px 25px padding, 1.1rem/300). */
.ui-v2 .toast-container .toast {
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr) 44px;
  align-items: start;
  justify-content: normal;
  gap: var(--sp-12);
  box-sizing: border-box;
  min-height: 44px;
  padding: var(--sp-12) var(--sp-4) var(--sp-12) var(--sp-16);
  border: 1px solid var(--rule);
  background-color: var(--surface-2) !important;
  border-radius: var(--r-md) !important;
  box-shadow: var(--shadow-menu);
  color: var(--ivory-100);
  font-family: var(--font-ui) !important;
  font-size: var(--fs-body-small);
  font-weight: 400;
  line-height: 20px;
  opacity: 0;
  transform: translateY(-8px);
}

.ui-v2 .toast-container .toast.toast-visible {
  opacity: 1;
  transform: none;
  animation: ca-toast-in var(--dur-2) var(--ease-out);
}

/* toast-notification.js removes the toast on animationend. */
.ui-v2 .toast-container .toast.toast-hiding {
  animation: ca-toast-out var(--dur-2) var(--ease-in) forwards;
}

@keyframes ca-toast-in {
  from {
    opacity: 0;
    transform: translateY(-8px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes ca-toast-out {
  from {
    opacity: 1;
    transform: none;
  }

  to {
    opacity: 0;
    transform: translateY(-8px);
  }
}

.ui-v2 .toast-container .toast-icon {
  width: 20px;
  height: 20px;
}

.ui-v2 .toast-container .toast-icon .ca-icon {
  display: block;
}

.ui-v2 .toast-container .toast-success .toast-icon .ca-icon {
  color: var(--success);
}

.ui-v2 .toast-container .toast-error .toast-icon .ca-icon {
  color: var(--danger-text);
}

.ui-v2 .toast-container .toast-warning .toast-icon .ca-icon {
  color: var(--warning);
}

.ui-v2 .toast-container .toast-info .toast-icon .ca-icon {
  color: var(--violet-400);
}

.ui-v2 .toast-container .toast-message {
  margin: 0;
  color: var(--ivory-100);
  font: 600 var(--fs-body-small)/20px var(--font-ui);
}

.ui-v2 .toast-container .toast-subtitle {
  margin: 0;
  color: var(--ivory-300);
  font: 400 13px/20px var(--font-ui);
  opacity: 1;
}

/* Static in the grid; the negative margins centre it on the first line
   without making a one-line toast taller than 44px. */
.ui-v2 .toast-container .toast-close {
  position: static;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  margin: calc(var(--sp-12) * -1) 0;
  border: 0;
  border-radius: var(--r-md);
  background-color: transparent;
  cursor: pointer;
}

/* Beats toast.css .toast-close:focus (blue outline) and Materialize
   button:focus; keyboard focus keeps the v2 ring below. */
.ui-v2 .toast-container .toast-close:focus {
  outline: none;
  background-color: transparent;
}

.ui-v2 .toast-container .toast-close:hover {
  background-color: var(--wash-hover);
}

.ui-v2 .toast-container .toast-close:focus-visible {
  outline: 2px solid var(--violet-300);
  outline-offset: -2px;
}

.ui-v2 .toast-container .toast-close .ca-icon {
  color: var(--ivory-500);
}

.ui-v2 .toast-container .toast-close:hover .ca-icon {
  color: var(--ivory-100);
}

.ui-v2 .toast-container .toast-progress {
  height: 2px;
  background: var(--rule);
  opacity: 1;
}

/* ─────────────────────────────────────────────────────────────
   FORCED COLOURS - keep every control boundary and state visible
   The browser drops background colours and gradients, box-shadows and
   ::after fills here, which is how the selected states above are drawn.
   Check, radio and switch get native drawing back; the other states are
   redrawn in system colours behind forced-color-adjust: none, with a
   system text colour wherever text sits.
   ───────────────────────────────────────────────────────────── */
@media (forced-colors: active) {
  .ui-v2 .ca-btn,
  .ui-v2 .ca-chip,
  .ui-v2 .ca-field__control,
  .ui-v2 input.ca-switch,
  .ui-v2 input.ca-check__input,
  .ui-v2 input.ca-radio__input {
    border: 1px solid ButtonText;
  }

  .ui-v2 .ca-notice {
    border: 1px solid CanvasText;
  }

  /* The system draws checked and unchecked. */
  .ui-v2 input.ca-check__input,
  .ui-v2 input.ca-radio__input,
  .ui-v2 input.ca-switch {
    -webkit-appearance: auto;
    appearance: auto;
  }

  /* The box-shadow ring is gone, so an outline marks the focused field. */
  .ui-v2 .ca-field__control:focus {
    outline: 2px solid Highlight;
    outline-offset: 2px;
  }

  .ui-v2 .ca-chip[aria-pressed="true"],
  .ui-v2 .ca-chip__input:checked + .ca-chip,
  .ui-v2 .ca-segmented__input:checked + .ca-segmented__option {
    forced-color-adjust: none;
    border-color: Highlight;
    background-color: Highlight;
    color: HighlightText;
  }

  .ui-v2 .ca-tabs__tab[aria-selected="true"]::after,
  .ui-v2 .ca-tabs__tab[aria-current="page"]::after {
    forced-color-adjust: none;
    background-color: Highlight;
  }

  /* Range: track line and fill, then thumbs and their focus ring. */
  .ui-v2 .ca-range__track::before {
    forced-color-adjust: none;
    background-image: linear-gradient(
      to right,
      GrayText var(--ca-range-from, 0%),
      Highlight var(--ca-range-from, 0%),
      Highlight var(--ca-range-to, 0%),
      GrayText var(--ca-range-to, 0%)
    );
  }

  .ui-v2 input.ca-range__input {
    forced-color-adjust: none;
  }

  .ui-v2 input.ca-range__input::-webkit-slider-thumb {
    background: ButtonText;
    box-shadow: none;
  }

  .ui-v2 input.ca-range__input::-moz-range-thumb {
    background: ButtonText;
    box-shadow: none;
  }

  body.ui-v2 .ca-range input.ca-range__input:focus-visible::-webkit-slider-thumb {
    box-shadow: 0 0 0 2px Canvas, 0 0 0 4px Highlight;
  }

  body.ui-v2 .ca-range input.ca-range__input:focus-visible::-moz-range-thumb {
    box-shadow: 0 0 0 2px Canvas, 0 0 0 4px Highlight;
  }
}
