/* ============================================================================
   Portmasters InlineAlert — inline-alert.css  (Visual System v2)
   ----------------------------------------------------------------------------
   WHY THIS COMPONENT EXISTS
   A toast is transient and lives at the viewport edge. The product ALSO signals
   outcome IN PLACE — a tinted box sitting inside the form, modal or panel it is
   talking about, which does not disappear. The product has never had a component
   for it: the same box is hand-rolled with Tailwind in five different places with
   three different radii (rounded-lg 8 / rounded-xl 12) and two different icon
   treatments (bare glyph vs filled round badge). This file is the ONE box.

   PROVENANCE — five real product instances, quoted file:line. Structure and copy
   come from these; nothing here is invented.

   (1) WARNING, single row — apps/website/src/views/booking-contact/BookingContact.tsx:484-489
         <div className="flex items-center gap-2 py-3 px-4 rounded-lg bg-warning-100">
           <AlertCircle className="w-5 h-5 text-warning-500 flex-shrink-0" />
           <Typography color="label-warning" size={2}>{t("pleaseCompleteProfile")}</Typography>
         </div>
       copy: pages.booking.contact.pleaseCompleteProfile
             "Please complete your profile to continue with booking."

   (2) SUCCESS, single row + filled badge — .../new-manifest/components/ViewDocumentModal.tsx:365-372
         <div className="mt-4 p-3 bg-success-50 border border-success-200 rounded-lg flex items-center gap-2">
           <div className="w-5 h-5 bg-success-500 rounded-full flex items-center justify-center">
             <Check className="w-3 h-3 text-white" /></div>
           <Typography size={3} color="label-success" className="font-medium">Document Approved</Typography>
         </div>
       copy: hardcoded "Document Approved" (ViewDocumentModal.tsx:370)

   (3) SUCCESS, shrink-to-fit chip — .../new-manifest/components/DocumentPdfModal.tsx:39-45
         <div className="inline-flex items-center p-3 rounded-xl bg-success-50 text-success-500">
           <CheckIcon className="w-4 h-4 me-2" />
           <Typography size={4} variant="label" color="label-success">File approved</Typography>
         </div>
       copy: hardcoded "File approved" (DocumentPdfModal.tsx:42)

   (4) ERROR, stacked + reason panel — .../new-manifest/components/DocumentPdfModal.tsx:50-60
         <div className="flex flex-col space-y-2 p-4 rounded-xl bg-error-50 text-error-500">
           <div className="flex items-center gap-2">
             <TriangleAlert className="w-4 h-4" />
             <Typography size={4} variant="label" color="description-error">File rejected</Typography>
           </div>
           <div className="border rounded-xl p-2 border-error-500 border-dashed">
             <Typography size={3} color="description-neutral">…reason…</Typography>
           </div>
         </div>
       copy: hardcoded "File rejected" (DocumentPdfModal.tsx:54) + the reason string
             (DocumentPdfModal.tsx:58) — note the product's own typo, "costumer".

   (5) MARKER chip, no icon — apps/line-forwarder/src/app/[locale]/dashboard/special-offer/layout.tsx:28-32
         <div className="bg-warning-100 px-3 py-1.5 rounded-lg">
           <Typography size={2} className="text-warning-800">{t("fclOnly")}</Typography></div>
       copy: specialOffer.layout.fclOnly  "FCL can only be special"

   WHAT V2 DECIDES (the founder's rule: structure from the product, look from V2)
     · RADIUS — the product ships 8px and 12px for the same box. V2 has ONE card
       tier: 12px (--radius-card). Every form here is 12px. The reason panel is a
       nested box, so it drops one tier to --radius-control (also 12) and keeps the
       source's dashed edge.
     · HEIGHT — py-3 + a 20px icon + py-3 = 44px. That USED to equal the V2 single-row
       control height; the founder reversed --control-h to 36px on 2026-08-04, so the
       padding sum now OUT-MEASURES the floor and the box renders 44, not 36. Recorded,
       not reflowed — closing it is a py-3 → py-2 spacing call. Pinned to --control-h so
       the floor cannot drift; the stacked and
       chip forms grow from the same floor. No box in this file is under 24px tall,
       so the 12px radius is legal everywhere (V2 radius/height rule).
     · TINT — light keeps the product recipe: --<status>-50 fill, --<status>-200
       hairline, --text-<status> ink. Dark does NOT keep it: a #FEFAEC fill on the
       #0f0715 page is a flashbang. Dark follows the house rule already ratified for
       tonal buttons (button.css:350-374) — the fill becomes a PLANE (--surface-card
       / --surface-plate) and the status is carried by the -400 ink plus a low-alpha
       status hairline. So the alert stays on the five-rung ladder in dark.
     · NO INNER SHADOWS. No gradient. One hairline, one flat tint.
     · The status is NEVER colour-only (WCAG 1.4.1): every variant pairs a distinct
       glyph SHAPE with worded copy, and the copy names the outcome by itself.

   Class model:
     box      .pm-inline-alert                       the region (role=status | role=alert)
       tone   .pm-inline-alert--warning | --error | --success | --info
       form   .pm-inline-alert--stacked              title row + reason panel (source 4)
              .pm-inline-alert--chip                 inline-flex, shrink-to-fit (source 3)
              .pm-inline-alert--marker               no icon, tint + ink only (source 5)
     icon     .pm-inline-alert__icon                 20px bare glyph in status ink (sources 1/3/4)
     badge    .pm-inline-alert__badge                20px filled round, white glyph (source 2)
       glyph  .pm-inline-alert__glyph                12px svg inside the badge
     body     .pm-inline-alert__body                 the text column
       title  .pm-inline-alert__title                the outcome line
       text   .pm-inline-alert__text                 supporting line (stacked form)
     reason   .pm-inline-alert__reason               dashed nested panel (source 4)
     actions  .pm-inline-alert__actions              optional shared .pm-btn slot
     a11y     .pm-inline-alert__sr                   visually-hidden tone prefix
   ============================================================================ */

@import url("../../tokens/tokens.css");
@import url("../../tokens/tokens-semantic.css");
@import url("../../tokens/tokens-type.css");  /* product type ramp — the 14 named Figma text styles */

/* ----------------------------------------------------------------------------
   BOX — the single-row default (sources 1 + 2). One flex row:
   [icon|badge] [body] [actions?]. --control-h (36px) is the declared floor; the
   source's py-3 + 20px icon computes to 44px, and THAT is what actually sizes the row.
   --_tint / --_edge / --_ink are set by the tone modifiers; the defaults make a
   bare .pm-inline-alert render as the neutral plate rather than as nothing.
   ---------------------------------------------------------------------------- */
.pm-inline-alert {
  --_tint: var(--surface-plate);      /* fill  — per-tone below */
  --_edge: var(--border);             /* hairline — per-tone below */
  --_ink:  var(--text-secondary);     /* icon + title ink — per-tone below */

  box-sizing: border-box;
  display: flex;
  align-items: center;                /* items-center (source 1/2) */
  gap: var(--space-2);                /* gap-2 = 8px (source 1/2) */
  min-height: var(--control-h);       /* 36px — V2 single-row height. The padding below (py-3 + 20px icon = 44) out-measures it, so the floor does not bind here; see the HEIGHT note. */
  padding-block: var(--space-3);      /* py-3 = 12px */
  padding-inline: var(--space-4);     /* px-4 = 16px (source 1) */
  background-color: var(--_tint);
  border: 1px solid var(--_edge);     /* source 2 ships the hairline; V2 gives it to every tone */
  border-radius: var(--radius-card);  /* 12px — ONE tier for the product's mixed 8/12 */
  color: var(--_ink);
  font-family: var(--font-body, "Inter", sans-serif);
}

/* ----------------------------------------------------------------------------
   ICON — the bare 20px glyph in status ink (source 1: w-5 h-5 text-warning-500;
   sources 3/4 use w-4 h-4 — normalised UP to the 20px box so the row keeps its
   vertical rhythm and every tone has one icon size). Decorative: aria-hidden.
   ---------------------------------------------------------------------------- */
.pm-inline-alert__icon {
  flex: none;                         /* flex-shrink-0 (source 1) */
  width: 20px;                        /* w-5 */
  height: 20px;                       /* h-5 */
  display: block;
  color: var(--_ink);                 /* glyph inherits the tone ink */
}

/* BADGE — the filled round alternative (source 2): a solid status disc with a
   white glyph. Same 20px box as the bare icon so the two are interchangeable
   without moving the row. --_fill is the SOLID status stop, not the tint. */
.pm-inline-alert__badge {
  --_fill: var(--success-500);        /* per-tone below */
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;                        /* w-5 h-5 (source 2) */
  height: 20px;
  border-radius: var(--radius-product-full);   /* rounded-full */
  background-color: var(--_fill);
  color: var(--text-on-dark);         /* text-white glyph */
}
.pm-inline-alert__glyph { width: 12px; height: 12px; display: block; }  /* w-3 h-3 (source 2) */

/* ----------------------------------------------------------------------------
   BODY / TITLE / TEXT
   Source typography: Typography size={2} (source 1) and size={3} variant="label"
   (sources 2/3/4) — i.e. the outcome line is a MEDIUM-weight body line. On the v2
   ramp that is body/strong (13.5 / 500 / 145% / −0.4%). The supporting line in the
   stacked form is body/default. Neither is a status chip, so neither takes
   label/status tracking.
   ---------------------------------------------------------------------------- */
.pm-inline-alert__body { min-width: 0; }   /* let long strings wrap inside flex */

.pm-inline-alert__title {
  margin: 0;
  color: var(--_ink);
  font-size: var(--type-body-strong-size);
  font-weight: var(--type-body-strong-weight);
  line-height: var(--type-body-strong-leading);
  letter-spacing: var(--type-body-strong-tracking);
  overflow-wrap: anywhere;            /* a booking ID or file name never overflows the box */
}

.pm-inline-alert__text {
  margin: var(--space-1) 0 0;         /* 4px under the title */
  color: var(--text-secondary);       /* color="description-neutral" (source 4 reason copy) */
  font-size: var(--type-body-default-size);
  font-weight: var(--type-body-default-weight);
  line-height: var(--type-body-default-leading);
  letter-spacing: var(--type-body-default-tracking);
}

/* ----------------------------------------------------------------------------
   FORM = STACKED (source 4) — title row on top, a nested reason panel under it.
   The source is flex-col space-y-2 p-4; the row inside keeps items-center gap-2.
   ---------------------------------------------------------------------------- */
.pm-inline-alert--stacked {
  display: block;                     /* the row and the panel stack */
  padding: var(--space-4);            /* p-4 = 16px (source 4) */
}
.pm-inline-alert--stacked > .pm-inline-alert__row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* REASON PANEL (source 4: border rounded-xl p-2 border-error-500 border-dashed).
   A nested box inside a tinted box — the dashed edge is what tells the reader the
   quoted text is the counterparty's words, not the product's. Ink is neutral
   secondary, verbatim from the source (color="description-neutral"). */
.pm-inline-alert__reason {
  margin-top: var(--space-2);         /* space-y-2 = 8px */
  padding: var(--space-2);            /* p-2 = 8px */
  border: 1px dashed var(--_edge);
  border-radius: var(--radius-control);  /* 12px — nested tier; box is >24px tall so this is legal */
  color: var(--text-secondary);
  font-size: var(--type-body-default-size);
  font-weight: var(--type-body-default-weight);
  line-height: var(--type-body-default-leading);
  letter-spacing: var(--type-body-default-tracking);
}

/* ----------------------------------------------------------------------------
   FORM = CHIP (source 3) — shrink-to-fit inline-flex. NOT a status pill: it is
   the same 12px box, just sized to its content. Keeps the --control-h floor (36px).
   ---------------------------------------------------------------------------- */
.pm-inline-alert--chip {
  display: inline-flex;               /* inline-flex (source 3) */
  width: auto;
  padding-inline: var(--space-3);     /* p-3 = 12px inline (source 3) */
}

/* FORM = MARKER (source 5) — tint + ink, NO icon, NO hairline. The product uses it
   as a standing rule label beside a page description ("FCL can only be special").
   Same box as the default, so it lines up with what it sits next to. NOTE: like the
   default it stands 44px off its py-3 padding while --control-h is 36px — the same
   recorded overshoot, not a separate one. */
.pm-inline-alert--marker {
  display: inline-flex;
  width: auto;
  padding-inline: var(--space-3);     /* px-3 = 12px (source 5) */
  border-color: transparent;          /* source ships no border on this one */
}

/* ----------------------------------------------------------------------------
   ACTIONS — an OPTIONAL shared Button slot, LINKED not re-implemented. Markup
   carries the real .pm-btn CVA (e.g. `.pm-btn .pm-btn--tonal .pm-btn--neutral
   .pm-btn--sm`) plus this positioning class; button.css owns every pixel of its
   look, size (36px), focus ring and dark repoint.
   ---------------------------------------------------------------------------- */
.pm-inline-alert__actions {
  display: flex;
  flex: none;
  gap: var(--space-2);
  margin-inline-start: auto;          /* float to the inline-end (flips in RTL) */
  align-self: center;
}
.pm-inline-alert__actions:empty { display: none; }

/* ============================================================================
   TONES — light. The product recipe, verbatim: --<status>-50 fill,
   --<status>-200 hairline, and the ratified --text-<status> ink role (which is
   the -700 stop and the only one that clears AA on these tints).
   Source (1) fills with warning-100 rather than warning-50; warning-50 is the
   value every OTHER tinted surface in the system uses (button.css:295 tonal), so
   the family is unified on -50 and the one-off -100 is dropped. That is a look
   decision, which is V2's to make; the structure and the string are unchanged.
   ============================================================================ */
.pm-inline-alert--warning {
  --_tint: var(--warning-50);   --_edge: var(--warning-200);  --_ink: var(--text-warning);
}
.pm-inline-alert--error {
  --_tint: var(--error-50);     --_edge: var(--error-200);    --_ink: var(--text-error-strong);
}
.pm-inline-alert--success {
  --_tint: var(--success-50);   --_edge: var(--success-200);  --_ink: var(--text-success);
}
.pm-inline-alert--info {
  --_tint: var(--info-50);      --_edge: var(--info-200);     --_ink: var(--text-info);
}

/* badge fills — the SOLID stop (source 2 is bg-success-500), one per tone */
.pm-inline-alert--warning .pm-inline-alert__badge { --_fill: var(--warning-500); }
.pm-inline-alert--error   .pm-inline-alert__badge { --_fill: var(--error-500);   }
.pm-inline-alert--success .pm-inline-alert__badge { --_fill: var(--success-500); }
.pm-inline-alert--info    .pm-inline-alert__badge { --_fill: var(--info-500);    }

/* ============================================================================
   TONES — dark. Following the ratified tonal-button rule (button.css:350-374):
   the coloured TINT is dropped and the box lands on a PLANE; the status survives
   in the ink (the -400 stops, which are the ones tokens-semantic.css measures as
   AA on the deep planes) plus a low-alpha status hairline so the box still reads
   as "this one is a warning" at a glance.
   Plane choice: --surface-card (#322639) is the plane a card-shaped box sits on.
   An alert nested INSIDE a card takes --surface-plate via --nested below, so two
   stacked boxes never paint the same value.
   ============================================================================ */
[data-theme="dark"] .pm-inline-alert {
  --_tint: var(--surface-card);
  --_edge: var(--border-strong);
  --_ink:  var(--text-secondary);
}
[data-theme="dark"] .pm-inline-alert--warning { --_ink: var(--text-warning); --_edge: rgba(240,196,66,.28); }  /* --warning-400 @28% */
[data-theme="dark"] .pm-inline-alert--error   { --_ink: var(--text-error);   --_edge: rgba(249,109,159,.28); } /* --error-400 @28% */
[data-theme="dark"] .pm-inline-alert--success { --_ink: var(--text-success); --_edge: rgba(37,226,169,.28); }  /* --success-400 @28% */
[data-theme="dark"] .pm-inline-alert--info    { --_ink: var(--text-info);    --_edge: rgba(150,176,250,.28); } /* --info-300 @28% */

/* Nested inside a card, the alert drops one plane so the two surfaces separate. */
[data-theme="dark"] .pm-inline-alert--nested { --_tint: var(--surface-plate); }
.pm-inline-alert--nested { --_tint: var(--surface-plate); }

/* Dark badge fills lift one stop, matching toast.css:318-321 — on the deep planes
   the -500 stops go muddy and the badge stops reading as a signal. */
[data-theme="dark"] .pm-inline-alert--warning .pm-inline-alert__badge { --_fill: var(--warning-400); color: var(--neutral-900); }
[data-theme="dark"] .pm-inline-alert--error   .pm-inline-alert__badge { --_fill: var(--error-400);   }
[data-theme="dark"] .pm-inline-alert--success .pm-inline-alert__badge { --_fill: var(--success-400); color: var(--neutral-900); }
[data-theme="dark"] .pm-inline-alert--info    .pm-inline-alert__badge { --_fill: var(--info-400);    }

/* ----------------------------------------------------------------------------
   A11y helper — visually-hidden tone prefix, so AT announces
   "Warning: Please complete your profile to continue with booking."
   ---------------------------------------------------------------------------- */
.pm-inline-alert__sr {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ----------------------------------------------------------------------------
   Reduced motion — this family ships no transition; the guard neutralises any
   future one (house convention, list.css:229 / card.css:101).
   ---------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .pm-inline-alert { transition: none; }
}

/* ============================================================================
   A11y contract (these styles assume this markup — set in the story):
     · warning / error  → role="alert"   (assertive: the user must act)
       success / info   → role="status"  (polite)
     · the icon or badge is aria-hidden="true"; a .pm-inline-alert__sr span names
       the tone, so the announcement is never colour-only.
     · the box is NOT dismissible. In the product an in-place alert stays until the
       condition clears (the profile is completed, the document is re-reviewed).
       If a caller adds a dismiss, it must be a real <button class="pm-btn …"> in
       .pm-inline-alert__actions with an aria-label — never a bare clickable div.
     · Do NOT use this for a transient outcome. That is Toast (bottom-center,
       react-toastify, toastId dedup) — see components/toast/toast.css.
   ============================================================================ */
