/* ============================================================================
   SPREEAI partner portal — standards layer
   Version 2.0 · September 14, 2026

   Fixes four issues that have each been raised in three or more design
   reviews. They keep coming back because they were ticketed per screen
   instead of being written down as rules, so this file is the rule.

   HOW TO LOAD
   Import spreeai-design-tokens.css FIRST, then the portal's own stylesheets,
   then this file LAST:

       import './spreeai-design-tokens.css';   // Figma-owned values
       import './portal.css';                  // existing app styles
       import './spreeai-portal-standards.css';// these rules win

   Order matters. The tokens file defines every var() used below.

   Import this LAST, after the portal's own stylesheets:
       import './spreeai-portal-standards.css';
   or
       <link rel="stylesheet" href="/css/spreeai-portal-standards.css">

   WHAT THIS FILE CANNOT DO ALONE
   Rule 1 (trailing icons) is only half solvable in CSS. Where the arrow is a
   pseudo-element or a nested <svg>, CSS removes it. Where the arrow is a
   literal character inside the label text — which is how most of the portal
   currently does it, e.g. <a>Export report ↗</a> — CSS cannot reach it.
   Run codemod-trailing-icons.mjs against the source for those.
   See README.md, section "Rollout".
   ========================================================================= */


/* ----------------------------------------------------------------------------
   0 · TOKENS

   Tokens now live in spreeai-design-tokens.css, generated from the Figma
   design system. Nothing in this file defines a value; it only consumes them.
   If a var() below is undefined, the tokens file was not imported first.

   Design system: https://www.figma.com/design/336bGaal4YVGEqc67Fd9nM/Design-System
   -------------------------------------------------------------------------- */

/* ----------------------------------------------------------------------------
   RULE 1 · NO TRAILING ICONS
   Raised Sep 8, Sep 9, Sep 10, Sep 14.

   THE RULE
   Text links and buttons carry no trailing glyph. The affordance is the
   underline on a link and the fill on a button, not an arrow.

   Leading icons are still allowed where the icon carries meaning the label
   does not (status, file type, destructive action). Trailing arrows never do:
   "Export report ↗" and "Export report" mean the same thing, so the arrow is
   decoration on a utility screen.

   THE ONE EXCEPTION
   Disclosure controls that genuinely change state — an accordion chevron, a
   select caret — keep their glyph, because there the icon encodes state the
   label cannot. Mark those with data-spree-disclosure so the sweep skips them.
   -------------------------------------------------------------------------- */

/* 1a · pseudo-element arrows */
a::after,
a::before,
button::after,
button::before,
[role="link"]::after,
[role="button"]::after {
  content: none !important;
}

/* 1b · nested icon elements that sit after the label */
a > svg:last-child:not([data-spree-icon="leading"]),
button > svg:last-child:not([data-spree-icon="leading"]),
a > .icon:last-child:not([data-spree-icon="leading"]),
button > .icon:last-child:not([data-spree-icon="leading"]),
a > [class*="arrow"],
button > [class*="arrow"],
a > [class*="external"],
button > [class*="external"] {
  display: none !important;
}

/* 1c · re-admit the exception */
[data-spree-disclosure]::after,
[data-spree-disclosure] > svg:last-child {
  content: "" !important;
  display: inline-flex !important;
}

/* 1d · link affordance, now that the arrow is gone.
   Underline is present by default, not only on hover. Raised Sep 10. */
.spree-link,
a[data-spree="link"] {
  font-family: var(--spree-font);
  font-size: var(--spree-text-body);
  color: var(--spree-ink-primary);
  text-decoration: underline;
  text-underline-offset: 0.18em;
  text-decoration-thickness: from-font;
}

.spree-link:hover,
a[data-spree="link"]:hover {
  color: var(--spree-ink-secondary);
}

.spree-link:focus-visible,
a[data-spree="link"]:focus-visible {
  outline: 2px solid var(--spree-ink-primary);
  outline-offset: 2px;
  border-radius: 2px;
}


/* ----------------------------------------------------------------------------
   RULE 2 · TOAST
   Raised Sep 10 and Sep 14. Said five times in one twelve-minute session.

   THE RULE
   A toast is readable at a glance from normal viewing distance or it has
   failed at its only job. 16px floor, 1.2 line height, no tightened tracking,
   no icon, no checkmark. The message states what happened in the same words
   as the control that caused it: "Publish" produces "Published".

   OPEN QUESTION — see README. "Kerning at 120%" is implemented here as
   line-height 1.2 with tracking reset to 0, because 120% letter-spacing would
   be roughly 19px of space between characters. Confirm before shipping.
   -------------------------------------------------------------------------- */

/* PORTAL SCOPE: this build uses role="status" on non-toast live regions
   (pagination counters, load-more announcements), so the generic
   [role="status"] / [role="alert"] selectors are scoped to the toast element.
   Flagged for Nicole in the QA action summary, addendum 5. */
.spree-toast,
#toast[role="status"],
#toast[role="alert"] {
  font-family: var(--spree-font);
  font-size: var(--spree-toast-size);
  line-height: var(--spree-toast-leading);
  letter-spacing: var(--spree-toast-tracking);
  min-width: var(--spree-toast-min-width);
  max-width: var(--spree-toast-max-width);

  display: flex;
  align-items: center;
  gap: var(--spree-space-3);
  padding: var(--spree-space-4) var(--spree-space-6);

  background: var(--spree-surface-inverse);
  color: var(--spree-ink-inverse);
  border: none;              /* Rule 3 */
  border-radius: var(--spree-radius-sm);
  box-shadow: none;          /* no shadows in the system */
}

/* No icons, no checkmarks, no status dots inside a toast. Raised Sep 10. */
.spree-toast svg,
.spree-toast .icon,
.spree-toast [class*="check"],
#toast[role="status"] svg,
#toast[role="alert"] svg {
  display: none !important;
}

/* The dismiss control is the only child that survives */
.spree-toast .spree-toast__dismiss {
  display: inline-flex !important;
  margin-left: auto;
  background: none;
  border: none;
  color: var(--spree-ink-inverse);
  cursor: pointer;
}


/* ----------------------------------------------------------------------------
   RULE 3 · SURFACES — NO STROKES, NO CREAM
   Raised Sep 8, Sep 10, Sep 14.

   THE RULE
   Separation is done with surface and space, not with a line. A container
   gets a background and padding. If a border is genuinely load-bearing —
   a table rule, an input field — it is 0.5px at 12% black. There is no
   second border weight and no cream. Cream is not in the palette.

   Run audit-standards.mjs to find every cream value currently in the source.
   -------------------------------------------------------------------------- */

.spree-surface,
.spree-card,
[data-spree="surface"] {
  background: var(--spree-surface-subtle);
  border: none;
  border-radius: var(--spree-radius-md);
  box-shadow: none;
  padding: var(--spree-space-6);
}

/* Fieldsets are the worst offender — the browser default draws a box.
   This is the events group in the webhooks screenshot. */
.spree-surface fieldset,
fieldset[data-spree="group"] {
  border: none;
  margin: 0;
  padding: 0;
  min-width: 0;
}

fieldset[data-spree="group"] > legend {
  padding: 0;
  margin-bottom: var(--spree-space-3);
  font-size: var(--spree-text-small);
  color: var(--spree-ink-secondary);
}

/* Borders that are allowed, at the one weight that exists */
.spree-table th,
.spree-table td,
.spree-input,
input[type="text"],
input[type="email"],
input[type="url"],
textarea,
select {
  border: var(--spree-border);
}

.spree-table th,
.spree-table td {
  border-width: 0 0 var(--spree-border-width) 0;
}

.spree-input,
input[type="text"],
input[type="email"],
input[type="url"],
textarea,
select {
  border-radius: var(--spree-radius-sm);
  padding: var(--spree-space-3) var(--spree-space-4);
  font-family: var(--spree-font);
  font-size: var(--spree-text-body);
  background: var(--spree-surface-raised);
  color: var(--spree-ink-primary);
}

/* Focus ring uses brand ink, never the browser's blue.
   The blue ring on the notifications close control is this. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--spree-ink-primary);
  outline-offset: 2px;
}


/* ----------------------------------------------------------------------------
   RULE 4 · CHECK GLYPHS COME FROM THE ICON LIBRARY
   Raised Sep 10 and Sep 14.

   THE RULE
   No hand-drawn or browser-default check marks. The check is Phosphor Check,
   masked so it inherits currentColor and never drifts in weight or size.

   This styles a real <input type="checkbox"> so keyboard, screen reader and
   form semantics all keep working. Markup contract is in reference-markup.html.

   Phosphor Icons is MIT licensed. If your build already bundles Phosphor,
   swap the inline data URI below for your bundled asset so there is one
   source of the path.
   -------------------------------------------------------------------------- */

.spree-checkbox {
  display: inline-flex;
  align-items: center;
  gap: var(--spree-space-3);
  font-family: var(--spree-font);
  font-size: var(--spree-text-body);
  color: var(--spree-ink-primary);
  cursor: pointer;
}

.spree-checkbox > input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  margin: 0;
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  border: var(--spree-border);
  border-radius: 4px;
  background: var(--spree-surface-raised);
  display: grid;
  place-content: center;
  cursor: pointer;
}

.spree-checkbox > input[type="checkbox"]::before {
  content: "";
  width: 14px;
  height: 14px;
  transform: scale(0);
  transition: transform 90ms ease-out;
  background-color: var(--spree-ink-inverse);

  /* Phosphor · Check · regular weight */
  --spree-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath d='M229.66,77.66l-128,128a8,8,0,0,1-11.32,0l-56-56a8,8,0,0,1,11.32-11.32L96,188.69,218.34,66.34a8,8,0,0,1,11.32,11.32Z'/%3E%3C/svg%3E");
  -webkit-mask-image: var(--spree-check);
  mask-image: var(--spree-check);
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.spree-checkbox > input[type="checkbox"]:checked {
  background: var(--spree-ink-primary);
  border-color: var(--spree-ink-primary);
}

.spree-checkbox > input[type="checkbox"]:checked::before {
  transform: scale(1);
}

.spree-checkbox > input[type="checkbox"]:indeterminate {
  background: var(--spree-ink-primary);
  border-color: var(--spree-ink-primary);
}

.spree-checkbox > input[type="checkbox"]:indeterminate::before {
  transform: scale(1);
  --spree-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath d='M216,128a8,8,0,0,1-8,8H48a8,8,0,0,1,0-16H208A8,8,0,0,1,216,128Z'/%3E%3C/svg%3E");
}

.spree-checkbox > input[type="checkbox"]:disabled {
  border-color: var(--spree-ink-tertiary);
  background: var(--spree-surface-subtle);
  cursor: not-allowed;
}

.spree-checkbox:has(> input:disabled) {
  color: var(--spree-ink-tertiary);
  cursor: not-allowed;
}

@media (prefers-reduced-motion: reduce) {
  .spree-checkbox > input[type="checkbox"]::before {
    transition: none;
  }
}


/* ----------------------------------------------------------------------------
   SELECTOR MAP — fill this in, 15 minutes with devtools
   The rules above target the portal's semantic elements and the new spree-*
   classes. Wherever the portal already has its own class for one of these
   components, add it here so the rule applies without touching every screen.

   Example:
       .Toast_root__x7k2 { ... }  →  add to the RULE 2 selector list
       .Card_shell__9fa1 { ... }  →  add to the RULE 3 selector list

   Keep additions in this block so there is one place to audit.
   -------------------------------------------------------------------------- */

/* Filled September 14, 2026 against the portal source (site/assets/).
   The portal is plain HTML/CSS/JS - classes below are the portal's own. */

/* -- RULE 2 · the portal toast (#toast / .toast) --------------------------
   Type and surface adopted now; the full DOM contract (dismiss control,
   flex layout per reference-markup.html) lands with the markup pass. */
.toast {
  font-family: var(--spree-font);
  font-size: var(--spree-toast-size);
  line-height: var(--spree-toast-leading);
  letter-spacing: var(--spree-toast-tracking);
  min-width: var(--spree-toast-min-width);
  max-width: var(--spree-toast-max-width);
  background: var(--spree-surface-inverse);
  color: var(--spree-ink-inverse);
  border: none;
  border-radius: var(--spree-radius-sm);
  box-shadow: none;
}

.toast strong,
.toast small {
  font-family: var(--spree-font);
  letter-spacing: var(--spree-toast-tracking);
  line-height: var(--spree-toast-leading);
}

.toast strong { font-size: var(--spree-toast-size); }
.toast small  { font-size: var(--spree-text-small); color: var(--ds-element-on-brand-secondary); }

/* Rule 2: no icons, checks or status glyphs inside a toast. The portal's
   icon span is hidden here; the showToast markup cleanup lands with the
   codemod pass. */
.toast > span { display: none !important; }

/* -- RULE 3 exception · catalog search ------------------------------------
   The input sits inside an already-styled shell (.v2-catalog-search), so the
   generic input border would re-create the box-in-box removed on Sep 14.
   The shell carries the affordance; the inner input stays bare. */
.v2-catalog-search input,
.v2-catalog-search input[type="text"] {
  border: none;
  background: transparent;
}

/* -- RULE 4 · the portal checkbox (.garment-check) ------------------------
   Same Phosphor Check mask as .spree-checkbox, applied to the existing
   portal class so garment select-all and row checks comply without a
   markup change. */
.garment-check > input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  margin: 0;
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  border: var(--spree-border);
  border-radius: 4px;
  background: var(--spree-surface-raised);
  display: grid;
  place-content: center;
  cursor: pointer;
}
.garment-check > input[type="checkbox"]::before {
  content: "";
  width: 14px;
  height: 14px;
  transform: scale(0);
  transition: transform 90ms ease-out;
  background-color: var(--spree-ink-inverse);
  --spree-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath d='M229.66,77.66l-128,128a8,8,0,0,1-11.32,0l-56-56a8,8,0,0,1,11.32-11.32L96,188.69,218.34,66.34a8,8,0,0,1,11.32,11.32Z'/%3E%3C/svg%3E");
  -webkit-mask-image: var(--spree-check);
  mask-image: var(--spree-check);
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}
.garment-check > input[type="checkbox"]:checked,
.garment-check > input[type="checkbox"]:indeterminate {
  background: var(--spree-ink-primary);
  border-color: var(--spree-ink-primary);
}
.garment-check > input[type="checkbox"]:checked::before {
  transform: scale(1);
}
.garment-check > input[type="checkbox"]:indeterminate::before {
  transform: scale(1);
  --spree-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath d='M216,128a8,8,0,0,1-8,8H48a8,8,0,0,1,0-16H208A8,8,0,0,1,216,128Z'/%3E%3C/svg%3E");
}
@media (prefers-reduced-motion: reduce) {
  .garment-check > input[type="checkbox"]::before { transition: none; }
}
