/* MDDS component classes.

   Pieces that are a component in Figma ("MDDS · 03 Components (web & apps)")
   but not an Angular component in code: each one is a CSS class recipe that
   the components using it apply in their templates. Behaviour (opening,
   closing, positioning, keyboard) always belongs to that parent component.

   Rules:
   - Hand-written. Unlike primitive/semantic/utilities.css, this file is not
     generated by the token sync: never regenerate or overwrite it from Figma.
   - Built only on semantic tokens (--md-spacing-*, --md-border-*, ...). No
     primitive tokens and no literal values, except two kinds of geometry
     Figma keeps outside its variables: shadow geometry, which lives in the
     effect style (as .md-elevation-*), and proportions drawn on the canvas,
     such as the status dot at 75% of its slot.
   - Loaded before every utilities.css, so a utility in the markup still
     overrides a recipe.
   - A piece people write by hand in templates (Badge) gets its own
     playground story, built with `markup` (playground/README.md). A piece
     only used inside other components (Dropdown Panel, Input) is shown
     through them.

   One region per piece, named after its Figma component: Dropdown Panel,
   Input, Badge and Status Dot so far; each new class-only piece is added
   below in its own region by the task that creates it. */


/* ═══════════════════════════════════════
   #region Dropdown Panel
   ═══════════════════════════════════════

   Surface that holds the options of a dropdown. Used by md-dropdown-menu and
   md-select. Figma: Dropdown Panel, Dropdown Group and Dropdown Divider
   (page "↳ Dropdowns", node 862:10056).

   These are the classes to use for any dropdown surface, instead of
   .dropdown-md from new-md.css. The screens that still use .dropdown-md move
   to this recipe in a later iteration; .dropdown-md is removed after that.

   Structure: the panel holds one or more groups; md-list-item entries go
   inside a group. Between two groups, a divider at the full panel width.

   One group:
     <div class="md-dropdown-panel" role="menu">
       <ul class="md-dropdown-panel__group" role="none">
         <li role="none"><md-list-item item-role="menuitem" ...></li>
       </ul>
     </div>

   Several groups:
     <div class="md-dropdown-panel" role="menu">
       <ul class="md-dropdown-panel__group" role="group" aria-label="...">...</ul>
       <div class="md-dropdown-panel__divider" role="separator"></div>
       <ul class="md-dropdown-panel__group" role="group" aria-label="...">...</ul>
     </div>

   A message entry (md-list-item variant="message", e.g. no results for the
   text typed) is feedback, not an option: the parent puts it inside a live
   region (role="status") so screen readers announce it when it appears.

   The panel sets no width: the parent gives it the width of the field that
   opens it (md-select) or of its longest option (md-dropdown-menu). Up to 10
   options are visible; beyond that the panel scrolls. That height depends on
   the md-list-item size: sm by default, --mn and --lg for the other two. */

.md-dropdown-panel {
  box-sizing: border-box;
  margin: 0;
  padding: var(--md-spacing-4xs) 0;
  overflow-y: auto;
  border: var(--md-border-width-sm) solid var(--md-border-subtle);
  border-radius: var(--md-radius-xs);
  background-color: var(--md-background-primary);
  /* elevation/sm, same geometry as .md-elevation-sm. */
  box-shadow: 0 2px 4px -1px var(--md-elevation-sm), 0 0 0 1px var(--md-elevation-edge);
  list-style: none;
  /* 10 sm options (padding 3xs + one label-lg line, with or without tag),
     plus the panel and group paddings and the panel border. */
  max-height: calc(
    10 * (2 * var(--md-spacing-3xs) + var(--md-text-label-lg-font-size) * var(--md-text-label-lg-line-height))
    + 4 * var(--md-spacing-4xs)
    + 2 * var(--md-border-width-sm)
  );
}

/* 10 mn options: padding 2xs + one label-lg line. */
.md-dropdown-panel.md-dropdown-panel--mn {
  max-height: calc(
    10 * (2 * var(--md-spacing-2xs) + var(--md-text-label-lg-font-size) * var(--md-text-label-lg-line-height))
    + 4 * var(--md-spacing-4xs)
    + 2 * var(--md-border-width-sm)
  );
}

/* 10 lg options: padding 2xs + one body-mn line. */
.md-dropdown-panel.md-dropdown-panel--lg {
  max-height: calc(
    10 * (2 * var(--md-spacing-2xs) + var(--md-text-body-mn-font-size) * var(--md-text-body-mn-line-height))
    + 4 * var(--md-spacing-4xs)
    + 2 * var(--md-border-width-sm)
  );
}

.md-dropdown-panel__group {
  margin: 0;
  padding: var(--md-spacing-4xs) var(--md-spacing-3xs);
  list-style: none;
}

/* Works on <div>, <li> or <hr>: the line is the background, not a border. */
.md-dropdown-panel__divider {
  display: block;
  height: var(--md-border-width-sm);
  /* Figma pads the line 2px above and below: half of spacing/4xs. */
  margin: calc(var(--md-spacing-4xs) / 2) 0;
  padding: 0;
  border: 0;
  background-color: var(--md-border-primary);
  list-style: none;
}

/* #endregion Dropdown Panel */


/* ═══════════════════════════════════════
   #region Input
   ═══════════════════════════════════════

   The field of a form control: label, the box, its content and the helper
   text. Figma: Input (page "↳ Inputs", node 221:1976), whose description
   says that every Type shares these styles: Select is md-select, the typing
   types (Text, Password, Search, Email) are the future md-input. Both build
   on this recipe instead of styling the box on their own.

   Structure:
     <div class="md-field md-field--sm">
       <label class="md-field__label" for="...">
         Label <span class="md-field__required" aria-hidden="true">*</span>
       </label>
       <button class="md-field__control" id="...">
         <span class="md-field__value">...</span>
         <i class="fmd fmd-i-chevron-down md-field__icon" aria-hidden="true"></i>
       </button>
       <span class="md-field__helper" id="...">...</span>
     </div>

   .md-field__value takes --placeholder while it shows the placeholder.

   Sizes (box height for one line): sm 32px, --mn 40px, --lg 48px.
   States on the block: --open (Figma Selected=True: its panel is open),
   --error and --disabled. Hover and keyboard focus come from the box
   itself; Focus is only the keyboard indicator, so it is :focus-visible.
   Success is not here yet: no field uses it. */

.md-field {
  display: flex;
  flex-direction: column;
  gap: var(--md-spacing-4xs);
}

.md-field.md-field--lg {
  gap: var(--md-spacing-3xs);
}

.md-field .md-field__label {
  margin: 0;
  color: var(--md-content-primary);
  font-family: var(--md-text-label-mn-font-family);
  font-size: var(--md-text-label-mn-font-size);
  line-height: var(--md-text-label-mn-line-height);
  letter-spacing: var(--md-text-label-mn-letter-spacing);
  font-weight: var(--md-text-label-mn-regular-font-weight);
}

.md-field.md-field--mn .md-field__label,
.md-field.md-field--lg .md-field__label {
  font-family: var(--md-text-label-lg-font-family);
  font-size: var(--md-text-label-lg-font-size);
  line-height: var(--md-text-label-lg-line-height);
  letter-spacing: var(--md-text-label-lg-letter-spacing);
  font-weight: var(--md-text-label-lg-regular-font-weight);
}

.md-field .md-field__required {
  color: var(--md-content-negative);
}

/* The box. Figma draws Focus as a 2px stroke: here a 1px border plus a 1px
   inset ring, so the box does not grow when it takes focus. */
.md-field .md-field__control {
  display: flex;
  box-sizing: border-box;
  align-items: center;
  gap: var(--md-spacing-3xs);
  width: 100%;
  margin: 0;
  padding: var(--md-spacing-3xs) var(--md-spacing-2xs);
  border: var(--md-border-width-sm) solid var(--md-border-primary);
  border-radius: var(--md-radius-xs);
  background-color: var(--md-background-primary);
  color: var(--md-content-primary);
  font-family: var(--md-text-label-mn-font-family);
  font-size: var(--md-text-label-mn-font-size);
  line-height: var(--md-text-label-mn-line-height);
  letter-spacing: var(--md-text-label-mn-letter-spacing);
  font-weight: var(--md-text-label-mn-regular-font-weight);
  text-align: left;
  cursor: pointer;
}

.md-field.md-field--mn .md-field__control {
  padding: var(--md-spacing-2xs);
  font-family: var(--md-text-label-lg-font-family);
  font-size: var(--md-text-label-lg-font-size);
  line-height: var(--md-text-label-lg-line-height);
  letter-spacing: var(--md-text-label-lg-letter-spacing);
  font-weight: var(--md-text-label-lg-regular-font-weight);
}

.md-field.md-field--lg .md-field__control {
  padding: var(--md-spacing-2xs) var(--md-spacing-xs);
  font-family: var(--md-text-body-mn-font-family);
  font-size: var(--md-text-body-mn-font-size);
  line-height: var(--md-text-body-mn-line-height);
  letter-spacing: var(--md-text-body-mn-letter-spacing);
  font-weight: var(--md-text-body-mn-regular-font-weight);
}

.md-field .md-field__value {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.md-field .md-field__value.md-field__value--placeholder {
  color: var(--md-content-tertiary);
}

/* Same color in every state, Focus and open included (Figma Input
   description). FMD glyphs fill their box at a 16px font-size, so 12px in sm
   and 16px above, as in the design. */
.md-field .md-field__icon {
  flex: none;
  color: var(--md-content-tertiary);
  font-size: var(--md-font-size-2);
  line-height: var(--md-line-height-1);
}

.md-field.md-field--mn .md-field__icon,
.md-field.md-field--lg .md-field__icon {
  font-size: var(--md-font-size-4);
}

.md-field .md-field__helper {
  color: var(--md-content-secondary);
  font-family: var(--md-text-label-mn-font-family);
  font-size: var(--md-text-label-mn-font-size);
  line-height: var(--md-text-label-mn-line-height);
  letter-spacing: var(--md-text-label-mn-letter-spacing);
  font-weight: var(--md-text-label-mn-regular-font-weight);
}

/* States. Same specificity on purpose, so the order decides: open over
   hover, error over both, focus over error, and disabled over everything. */

.md-field .md-field__control:hover {
  border-color: var(--md-border-secondary);
}

.md-field.md-field--open .md-field__control {
  border-color: var(--md-border-secondary);
}

.md-field.md-field--error .md-field__control {
  border-color: var(--md-border-negative);
}

.md-field.md-field--error .md-field__helper {
  color: var(--md-content-negative);
}

.md-field .md-field__control:focus-visible {
  border-color: var(--md-border-focus);
  box-shadow: inset 0 0 0 var(--md-border-width-sm) var(--md-border-focus);
  outline: none;
}

.md-field.md-field--disabled .md-field__control {
  border-color: var(--md-border-disabled);
  background-color: var(--md-background-disabled);
  cursor: not-allowed;
}

.md-field.md-field--disabled .md-field__label,
.md-field.md-field--disabled .md-field__value,
.md-field.md-field--disabled .md-field__helper {
  color: var(--md-content-disabled);
}

/* #endregion Input */


/* ═══════════════════════════════════════
   #region Badge
   ═══════════════════════════════════════

   Read-only label for a status, a category or a short value (text or a
   number, often coming from the back end). Figma: Badge (page
   "↳ Badges & Chips", node 925:11479). It does not open anything nor react
   to clicks: anything interactive (filter, select, remove) is a Chip.

   Structure:
     <span class="md-badge md-badge--mn md-badge--positive">{{ label }}</span>

     <span class="md-badge md-badge--sm md-badge--neutral md-badge--bordered">
       <span class="md-status-dot md-status-dot--positive" aria-hidden="true"></span>
       Active
     </span>

     <span class="md-badge md-badge--lg md-badge--info">
       <i class="fmd fmd-i-info-circle" aria-hidden="true"></i>
       Label
     </span>

     Text that may be longer than its container (a file name, a room...):
     <span class="md-badge md-badge--sm md-badge--brand" title="{{ name }}">
       <span class="md-badge__label">{{ name }}</span>
     </span>

   Color: --brand (default), --neutral, --muted, --positive, --negative,
   --notice, --info, --note (the md-message palette plus muted, a grey for
   inactive or occupied states; note uses the discovery tokens). Neutral has a
   white background: on white surfaces use it with --bordered. The text always
   names the status; color is never the only cue.

   Size: --2xs, --xs, --sm (default), --mn, --lg. The height (12 / 16 / 24 /
   32 / 40) comes from the text line plus the vertical padding, it is never
   set by hand.

   Width: the badge hugs its text and never grows past its container
   (max-width: 100%). Short text can go bare; text that may not fit goes in
   .md-badge__label, which truncates it on one line with an ellipsis only
   when it overflows. Give it a title (or a tooltip) with the full text.

   Shape: radius xs by default, --full for a pill.
   Border: --bordered draws a 1px line inside the box (inset shadow), so it
   changes neither the height nor the width.

   Icons (.fmd) and a status dot are optional on either side of the text,
   except in --2xs, which is text only. Before the text goes an icon or a
   status dot, never both. Icons take the text color. The status dot takes
   the icon slot, except in sm, where it takes the 2xs slot (12) instead of
   16. */

.md-badge,
.md-badge.md-badge--brand {
  display: inline-flex;
  box-sizing: border-box;
  align-items: center;
  gap: var(--md-spacing-4xs);
  padding: var(--md-spacing-4xs) var(--md-spacing-2xs);
  border-radius: var(--md-radius-xs);
  background-color: var(--md-background-tertiary);
  color: var(--md-content-brand-primary);
  font-family: var(--md-text-label-mn-font-family);
  font-size: var(--md-text-label-mn-font-size);
  line-height: var(--md-text-label-mn-line-height);
  letter-spacing: var(--md-text-label-mn-letter-spacing);
  font-weight: var(--md-text-label-mn-semibold-font-weight);
  /* Never shrinks inside a flex container (e.g. a cell with several
     badges) unless it has a label to truncate, see below. max-width keeps
     it inside any other container. */
  flex: none;
  min-width: 0;
  max-width: 100%;
  white-space: nowrap;
  vertical-align: middle;
}

/* Truncates only when the badge reaches the width of its container. A
   bare text node cannot take an ellipsis inside a flex box: it needs this
   element. Only a badge with a label may shrink in a flex container. */
.md-badge:has(> .md-badge__label) {
  flex-shrink: 1;
}

.md-badge > .md-badge__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Icon slot: the icon font and the status dot are sized by font-size. The
   slot sizes (12 / 16 / 24) are the spacing steps of the same value: there
   are no icon size tokens. */
.md-badge > .fmd,
.md-badge > .md-status-dot {
  flex: none;
  font-size: var(--md-spacing-xs);
  line-height: 1;
}

/* In sm the status dot takes the 2xs slot (12, a 9px dot), not the 16 of
   the icons: at 16 the dot is too heavy next to the 12px text. */
.md-badge > .md-status-dot {
  font-size: var(--md-spacing-2xs);
}

/* sizes */

.md-badge.md-badge--2xs {
  padding: var(--md-spacing-none) var(--md-spacing-4xs);
  font-family: var(--md-text-label-sm-font-family);
  font-size: var(--md-text-label-sm-font-size);
  line-height: var(--md-text-label-sm-line-height);
  letter-spacing: var(--md-text-label-sm-letter-spacing);
  font-weight: var(--md-text-label-sm-semibold-font-weight);
}

/* 2xs is text only. */
.md-badge.md-badge--2xs > .fmd,
.md-badge.md-badge--2xs > .md-status-dot {
  display: none;
}

.md-badge.md-badge--xs {
  padding: var(--md-spacing-none) var(--md-spacing-3xs);
}

.md-badge.md-badge--xs > .fmd,
.md-badge.md-badge--xs > .md-status-dot {
  font-size: var(--md-spacing-2xs);
}

/* sm is the base. */

.md-badge.md-badge--mn {
  gap: var(--md-spacing-3xs);
  font-family: var(--md-text-body-mn-font-family);
  font-size: var(--md-text-body-mn-font-size);
  line-height: var(--md-text-body-mn-line-height);
  letter-spacing: var(--md-text-body-mn-letter-spacing);
  font-weight: var(--md-text-body-mn-semibold-font-weight);
}

.md-badge.md-badge--mn > .md-status-dot {
  font-size: var(--md-spacing-xs);
}

.md-badge.md-badge--lg {
  gap: var(--md-spacing-3xs);
  padding: var(--md-spacing-3xs) var(--md-spacing-xs);
  font-family: var(--md-text-body-lg-font-family);
  font-size: var(--md-text-body-lg-font-size);
  line-height: var(--md-text-body-lg-line-height);
  letter-spacing: var(--md-text-body-lg-letter-spacing);
  font-weight: var(--md-text-body-lg-semibold-font-weight);
}

.md-badge.md-badge--lg > .fmd,
.md-badge.md-badge--lg > .md-status-dot {
  font-size: var(--md-spacing-sm);
}

/* shape */

.md-badge.md-badge--full {
  border-radius: var(--md-radius-full);
}

/* colors (brand is the base) */

.md-badge.md-badge--neutral {
  background-color: var(--md-background-primary);
  color: var(--md-content-primary);
}

.md-badge.md-badge--muted {
  background-color: var(--md-background-secondary);
  color: var(--md-content-primary);
}

.md-badge.md-badge--positive {
  background-color: var(--md-background-positive-subtle);
  color: var(--md-content-positive-bold);
}

.md-badge.md-badge--negative {
  background-color: var(--md-background-negative-subtle);
  color: var(--md-content-negative-bold);
}

.md-badge.md-badge--notice {
  background-color: var(--md-background-notice-subtle);
  color: var(--md-content-notice-bold);
}

.md-badge.md-badge--info {
  background-color: var(--md-background-info-subtle);
  color: var(--md-content-info-bold);
}

.md-badge.md-badge--note {
  background-color: var(--md-background-discovery-subtle);
  color: var(--md-content-discovery-bold);
}

/* border: one rule per color, so the badge exposes no extra custom property.
   The line is an inset shadow, so it adds no size. Forced-colors modes
   (Windows high contrast) drop shadows, so a transparent outline drawn at
   the same place keeps the line there: the system paints it in its own
   color, and an outline never adds size either. */

.md-badge.md-badge--bordered {
  box-shadow: inset 0 0 0 var(--md-border-width-sm) var(--md-border-brand-secondary);
  outline: var(--md-border-width-sm) solid transparent;
  outline-offset: calc(-1 * var(--md-border-width-sm));
}

.md-badge.md-badge--bordered.md-badge--neutral {
  box-shadow: inset 0 0 0 var(--md-border-width-sm) var(--md-border-primary);
}

.md-badge.md-badge--bordered.md-badge--muted {
  box-shadow: inset 0 0 0 var(--md-border-width-sm) var(--md-border-secondary);
}

.md-badge.md-badge--bordered.md-badge--positive {
  box-shadow: inset 0 0 0 var(--md-border-width-sm) var(--md-border-positive);
}

.md-badge.md-badge--bordered.md-badge--negative {
  box-shadow: inset 0 0 0 var(--md-border-width-sm) var(--md-border-negative);
}

.md-badge.md-badge--bordered.md-badge--notice {
  box-shadow: inset 0 0 0 var(--md-border-width-sm) var(--md-border-notice);
}

.md-badge.md-badge--bordered.md-badge--info {
  box-shadow: inset 0 0 0 var(--md-border-width-sm) var(--md-border-info);
}

.md-badge.md-badge--bordered.md-badge--note {
  box-shadow: inset 0 0 0 var(--md-border-width-sm) var(--md-border-discovery);
}

/* #endregion Badge */


/* ═══════════════════════════════════════
   #region Status Dot
   ═══════════════════════════════════════

   Status indicator that sits in an icon slot, mainly the leading slot of a
   neutral Badge. Figma: Status Dot (page "↳ Badges & Chips", node
   925:13730). Its own class, composed inside the badge markup, not a Badge
   modifier.

   Structure:
     <span class="md-status-dot md-status-dot--negative" aria-hidden="true"></span>

   Color: --positive, --negative, --notice, --info, --note (note uses the
   discovery token), --muted (the text color of the muted badge).
   Decorative: the text next to it names the status.

   Like an icon, it takes the slot size from font-size (1em): the circle is
   75% of the slot and the margin fills the rest, as in Figma (18 in 24). */

.md-status-dot {
  display: inline-block;
  flex: none;
  width: 0.75em;
  height: 0.75em;
  margin: 0.125em;
  border-radius: var(--md-radius-full);
  background-color: currentColor;
}

.md-status-dot.md-status-dot--positive {
  background-color: var(--md-content-positive);
}

.md-status-dot.md-status-dot--negative {
  background-color: var(--md-content-negative);
}

.md-status-dot.md-status-dot--notice {
  background-color: var(--md-content-notice);
}

.md-status-dot.md-status-dot--info {
  background-color: var(--md-content-info);
}

.md-status-dot.md-status-dot--note {
  background-color: var(--md-content-discovery);
}

.md-status-dot.md-status-dot--muted {
  background-color: var(--md-content-primary);
}

/* #endregion Status Dot */
