/*
 * ForMe's plain-CSS rendition of the TasteRay design system (tasteray-mvp DESIGN.md, pinned in
 * design-system.lock.json). Everything in this file is the system's; nothing is ForMe's own.
 *
 * ForMe has no React, Tailwind or shadcn (DESIGN.md § 10, "Hono and plain CSS"), so the components
 * the mvp app renders as `app/components/ui/<name>.tsx` are written here once as classes, each
 * reproducing its guideline in `design/components/<Name>.md`. A colour, radius, shadow, easing,
 * duration or type value comes from `var(--token)` (public/styles/design/tokens.css); the only
 * literals are a component's own geometry (a 44px button is `h-11` in the system too) and the
 * `rgb(0 0 0 / .6)` the scrim is defined as.
 *
 * Load order on every page: fonts.css, design/tokens.css, system.css, then the page's own CSS.
 *
 *   Base        html, body, ::selection, :focus-visible, a, .sr-only, reduced motion
 *   Button      .btn  + --default --secondary --outline --ghost --destructive --link --card --inverse
 *                     + sizes --xs --sm --lg, icons --icon-xs --icon-sm --icon --icon-lg
 *   Badge       .badge + --secondary --outline --primary --product --user --destructive --success --warning
 *   Card        .card, .card__title, .card__description
 *   Input       .input + --sm --lg, --ray (the chat composer's edge)
 *   Progress    .progress + --sm --md --lg --user, .progress__fill
 *   Marker      .marker, .marker-on, .marker-prose
 *   Overlay     .dialog (the whole Dialog surface), .overlay-surface (its ground alone)
 *   Avatar, Separator, Spinner, Popup scrim
 *
 * The named text styles (`.text-display`, `.text-body`, ...) are in tokens.css, not here.
 */

/* ---------------------------------------------------------------- base --- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* One dark world: there is no light theme and no `dark:` branch (DESIGN.md § 2). */
html {
  background: var(--background);
  color-scheme: dark;
  -webkit-text-size-adjust: 100%;
  scrollbar-width: thin;
  scrollbar-color: var(--accent) var(--card);
}

body {
  background: var(--background);
  color: var(--foreground);
  font-family: var(--type-family-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

::selection {
  background: color-mix(in srgb, var(--primary) 40%, transparent);
  color: var(--foreground);
}

/* The system's one focus indicator: the ring colour, 2px, 2px off the edge. No glow. */
:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
}

/* Product voice as text: links are Ray's ink. */
a {
  color: var(--ink-product);
  transition: color var(--duration-fast) var(--ease-settle);
}

a:hover {
  text-decoration: underline;
}

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

/* Reduced motion (mvp app/globals.css): durations collapse and nothing spins. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* -------------------------------------------------------------- button --- */
/*
 * Button.md. `.btn` is the structure and the `default` size; a variant says how much the action
 * matters (one `.btn--default` per screen region), a size modifier replaces the size. A bare
 * `.btn` reads as `.btn--default`. An `<a class="btn">` is a link that looks like a button.
 */

.btn {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  height: 2.75rem; /* h-11 */
  margin: 0;
  padding: 0 var(--space-5);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background-clip: padding-box;
  /* default variant */
  background-color: var(--primary-strong);
  color: var(--primary-foreground);
  /* text-button, written out so the label keeps its face when a caller changes the size class */
  font-family: var(--type-family-display);
  font-size: var(--type-button-size);
  line-height: var(--type-button-line-height);
  font-weight: var(--type-button-weight);
  letter-spacing: var(--type-button-tracking);
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition:
    color var(--duration-fast) var(--ease-settle),
    background-color var(--duration-fast) var(--ease-settle),
    border-color var(--duration-fast) var(--ease-settle),
    opacity var(--duration-fast) var(--ease-settle),
    filter var(--duration-fast) var(--ease-settle),
    scale var(--duration-fast) var(--ease-settle);
}

/* A link styled as a button keeps its label colour on hover (the base `a:hover` underlines). */
.btn:hover {
  text-decoration: none;
}

.btn svg,
.btn [data-icon] {
  display: block;
  flex-shrink: 0;
  width: 1rem;
  height: 1rem;
  pointer-events: none;
}

/* An icon trims the padding on its side. */
.btn:has([data-icon='inline-start']) {
  padding-left: 1.125rem; /* pl-4.5 */
}

.btn:has([data-icon='inline-end']) {
  padding-right: 1.125rem; /* pr-4.5 */
}

/* Pressed: a 3% shrink. Under reduced motion there is no scale. */
.btn:active:not(:disabled, [aria-disabled='true']) {
  scale: 0.97;
}

.btn[aria-invalid='true'] {
  border-color: var(--destructive);
}

.btn:disabled,
.btn[aria-disabled='true'] {
  opacity: 0.4;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .btn:active:not(:disabled, [aria-disabled='true']) {
    scale: 1;
  }
}

/* Variants. Hover brightens or darkens a solid and steps a surface for the rest. */

.btn--default {
  background-color: var(--primary-strong);
  color: var(--primary-foreground);
}

.btn--secondary {
  background-color: var(--secondary);
  color: var(--foreground);
  border-color: var(--border-control);
}

.btn--outline {
  background-color: transparent;
  color: var(--foreground);
  border-color: var(--border-control-strong);
}

.btn--ghost {
  background-color: transparent;
  color: inherit;
}

.btn--destructive {
  background-color: var(--destructive-strong);
  color: var(--destructive-foreground);
}

.btn--link {
  background-color: transparent;
  color: var(--ink-product);
  text-underline-offset: 4px;
}

.btn--card {
  background-color: var(--surface-control-active);
  color: var(--foreground);
}

.btn--inverse {
  background-color: var(--inverse);
  color: var(--inverse-foreground);
}

@media (hover: hover) {
  .btn:hover,
  .btn--default:hover {
    filter: brightness(1.1);
  }

  .btn--secondary:hover,
  .btn--secondary[aria-expanded='true'] {
    background-color: var(--muted);
    filter: none;
  }

  .btn--outline:hover,
  .btn--outline[aria-expanded='true'],
  .btn--ghost:hover,
  .btn--ghost[aria-expanded='true'] {
    background-color: var(--surface-control);
    filter: none;
  }

  .btn--ghost:hover,
  .btn--ghost[aria-expanded='true'] {
    color: var(--foreground);
  }

  .btn--destructive:hover {
    filter: brightness(0.95);
  }

  .btn--link:hover {
    background-color: transparent;
    filter: none;
    text-decoration: underline;
  }

  .btn--card:hover {
    background-color: var(--surface-control-hover);
    filter: none;
  }

  .btn--inverse:hover {
    filter: brightness(0.9);
  }
}

/* Sizes: the height, the type, the padding and the gap. */

.btn--xs {
  height: 1.75rem; /* h-7 */
  padding: 0 var(--space-3);
  gap: var(--space-1);
  font-size: var(--type-label-size);
  line-height: var(--type-label-line-height);
  font-weight: var(--type-label-weight);
  letter-spacing: var(--type-label-tracking);
}

.btn--xs:has([data-icon='inline-start']) {
  padding-left: 0.625rem; /* pl-2.5 */
}

.btn--xs:has([data-icon='inline-end']) {
  padding-right: 0.625rem; /* pr-2.5 */
}

.btn--sm {
  height: 2.25rem; /* h-9 */
  padding: 0 var(--space-4);
  font-size: var(--type-label-size);
  line-height: var(--type-label-line-height);
  font-weight: var(--type-label-weight);
  letter-spacing: var(--type-label-tracking);
}

.btn--sm:has([data-icon='inline-start']) {
  padding-left: 0.875rem; /* pl-3.5 */
}

.btn--sm:has([data-icon='inline-end']) {
  padding-right: 0.875rem; /* pr-3.5 */
}

.btn--lg {
  height: 3.25rem; /* h-13 */
  padding: 0 var(--space-6);
  gap: 0.625rem; /* gap-2.5 */
}

.btn--lg svg,
.btn--lg [data-icon] {
  width: 1.25rem;
  height: 1.25rem;
}

.btn--lg:has([data-icon='inline-start']) {
  padding-left: 1.375rem; /* pl-5.5 */
}

.btn--lg:has([data-icon='inline-end']) {
  padding-right: 1.375rem; /* pr-5.5 */
}

/* Icon-only: a round, square-sized button. Give it an aria-label. */

.btn--icon-xs,
.btn--icon-sm,
.btn--icon,
.btn--icon-lg {
  padding: 0;
  border-radius: var(--radius-full);
}

.btn--icon-xs {
  width: 1.75rem;
  height: 1.75rem;
}

.btn--icon-sm {
  width: 2.25rem;
  height: 2.25rem;
}

.btn--icon {
  width: 2.75rem;
  height: 2.75rem;
}

.btn--icon-lg {
  width: 3.25rem;
  height: 3.25rem;
}

.btn--icon-lg svg,
.btn--icon-lg [data-icon] {
  width: 1.5rem;
  height: 1.5rem;
}

/* --------------------------------------------------------------- badge --- */
/*
 * Badge.md. The system's one pill, 24px. What changes between variants is who is speaking, never how
 * loud it is: no tint, a neutral wash or a hairline in the colour of the voice. A sentence is not a
 * badge. On a poster or an icon, use --secondary (opaque), not the translucent default.
 */

.badge {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  width: fit-content;
  height: 1.5rem; /* h-6 */
  padding: 0 0.625rem; /* px-2.5 */
  overflow: hidden;
  border: 1px solid var(--border-control);
  border-radius: var(--radius-full);
  background-color: var(--surface-control);
  color: var(--fg-secondary);
  font-family: var(--type-family-display);
  font-size: var(--type-label-size);
  line-height: var(--type-label-line-height);
  font-weight: var(--type-label-weight);
  letter-spacing: var(--type-label-tracking);
  white-space: nowrap;
  text-decoration: none;
  transition:
    color var(--duration-fast) var(--ease-settle),
    background-color var(--duration-fast) var(--ease-settle),
    border-color var(--duration-fast) var(--ease-settle);
}

.badge:hover {
  text-decoration: none;
}

.badge svg,
.badge [data-icon] {
  display: block;
  flex-shrink: 0;
  width: 0.75rem;
  height: 0.75rem;
  pointer-events: none;
}

.badge:has([data-icon='inline-start']) {
  padding-left: var(--space-2);
}

.badge:has([data-icon='inline-end']) {
  padding-right: var(--space-2);
}

.badge[aria-invalid='true'] {
  border-color: var(--destructive);
}

.badge--secondary {
  background-color: var(--secondary);
}

.badge--outline {
  background-color: transparent;
  border-color: var(--border-control-strong);
}

.badge--primary {
  background-color: var(--primary-strong);
  border-color: transparent;
  color: var(--primary-foreground);
}

/* Ray's ink: a blue hairline, no fill. */
.badge--product {
  background-color: transparent;
  border-color: color-mix(in srgb, var(--primary) 40%, transparent);
  color: var(--ink-product);
}

/* The user's own: a chip they picked, a receipt for what they did. */
.badge--user {
  background-color: transparent;
  border-color: color-mix(in srgb, var(--mark-user) 40%, transparent);
  color: var(--mark-user);
}

.badge--destructive {
  background-color: transparent;
  border-color: color-mix(in srgb, var(--destructive) 40%, transparent);
  color: var(--destructive);
}

.badge--success {
  background-color: transparent;
  border-color: color-mix(in srgb, var(--success) 40%, transparent);
  color: var(--success);
}

.badge--warning {
  background-color: transparent;
  border-color: color-mix(in srgb, var(--warning) 40%, transparent);
  color: var(--warning);
}

@media (hover: hover) {
  a.badge:hover {
    background-color: var(--surface-control-hover);
  }

  a.badge--secondary:hover {
    background-color: var(--muted);
  }

  a.badge--outline:hover,
  a.badge--product:hover,
  a.badge--user:hover,
  a.badge--destructive:hover,
  a.badge--success:hover,
  a.badge--warning:hover {
    background-color: transparent;
  }

  a.badge--primary:hover {
    background-color: var(--primary-strong);
    filter: brightness(1.1);
  }
}

/* ---------------------------------------------------------------- card --- */
/*
 * Card.md. A raised surface that holds one idea: a title, what it says, what to do about it. Depth
 * is a surface step and a hairline, never a shadow, a tint or an accent edge. A card in a card is
 * the ground.
 */

.card {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-5);
  border: 1px solid var(--border-hairline);
  border-radius: var(--radius-lg);
  background-color: var(--card);
  color: var(--card-foreground);
  box-shadow: none;
}

/* A card in a card is the ground, and so is a card on an overlay (.dialog, .overlay-surface, below). */
.card .card,
:is(.dialog, .overlay-surface) .card {
  background-color: var(--background);
}

.card__title {
  font-family: var(--type-family-display);
  font-size: var(--type-title-sm-size);
  line-height: var(--type-title-sm-line-height);
  font-weight: var(--type-title-sm-weight);
  letter-spacing: var(--type-title-sm-tracking);
}

.card__description {
  font-family: var(--type-family-body);
  font-size: var(--type-body-sm-size);
  line-height: var(--type-body-sm-line-height);
  font-weight: var(--type-body-sm-weight);
  letter-spacing: var(--type-body-sm-tracking);
  color: var(--muted-foreground);
}

/* --------------------------------------------------------------- input --- */
/*
 * Input.md, on an `<input>` or a `<textarea>`. Bordered, no fill: the field you speak into. The
 * edge is --input (3:1 on every surface, the only "type here" cue); focus turns it --primary and
 * adds the ring; invalid turns it --destructive. A field always has a <label>.
 */

.input {
  display: block;
  width: 100%;
  min-width: 0;
  height: 2.75rem; /* md: h-11 */
  margin: 0;
  padding: 0 0.875rem; /* px-3.5 */
  border: 1px solid var(--input);
  border-radius: var(--radius-md);
  background-color: transparent;
  color: var(--foreground);
  /* text-body */
  font-family: var(--type-family-body);
  font-size: var(--type-body-size);
  line-height: var(--type-body-line-height);
  font-weight: var(--type-body-weight);
  letter-spacing: var(--type-body-tracking);
  outline: none;
  transition:
    border-color var(--duration-fast) var(--ease-settle),
    opacity var(--duration-fast) var(--ease-settle);
}

textarea.input {
  height: auto;
  min-height: 4rem; /* min-h-16 */
  padding: 0.625rem 0.875rem; /* py-2.5 px-3.5 */
  field-sizing: content;
}

.input::placeholder {
  color: var(--muted-foreground);
  opacity: 1;
}

/* Focus: the edge turns blue, then the ring. `.input { outline: none }` above outranks the base
   :focus-visible outline, so the ring is restated here. */
.input:focus-visible {
  border-color: var(--primary);
  outline: 2px solid var(--ring);
  outline-offset: 2px;
}

.input[aria-invalid='true'] {
  border-color: var(--destructive);
}

.input:disabled {
  opacity: 0.4;
  pointer-events: none;
}

.input--sm {
  height: 2.25rem; /* h-9 */
}

.input--lg {
  height: 3.25rem; /* h-13 */
}

/* The chat composer's field (InputGroup variant="ray"): Ray's blue at rest, 4.65:1 on the ground. */
.input--ray {
  border-color: var(--primary);
}

/* iOS Safari zooms the page in when a focused field renders below 16px, so a touch pointer gets 16. */
@media (pointer: coarse) {
  .input {
    font-size: 16px;
  }
}

/* ------------------------------------------------------------ progress --- */
/*
 * Progress.md. A measure the person can watch grow, as a solid fill on a quiet track: --primary for
 * a product measure, --mark-user (.progress--user) for the user's own. Never a gradient or a glow.
 * Set the value on the bar: <div class="progress" role="progressbar" style="--value: 62%">. The fill
 * slides along the track by a transform, not by width.
 */

.progress {
  --value: 0%;
  position: relative;
  width: 100%;
  height: 0.375rem; /* default: h-1.5 */
  overflow: hidden;
  border-radius: var(--radius-full);
  background-color: var(--track-progress);
}

.progress--sm {
  height: 0.25rem; /* h-1 */
}

.progress--md {
  height: 0.75rem; /* h-3 */
}

.progress--lg {
  height: 1rem; /* h-4 */
}

.progress__fill {
  width: 100%;
  height: 100%;
  border-radius: var(--radius-full);
  background-color: var(--primary);
  transform: translateX(calc(var(--value) - 100%));
  transition: transform var(--duration-base) var(--ease-settle);
}

.progress--user .progress__fill {
  background-color: var(--mark-user);
}

/* -------------------------------------------------------------- marker --- */
/*
 * The marker pen, the system's one signature device (mvp app/globals.css). A band of --marker-ink
 * flush to the bottom of an inline box, painted under the glyphs. `.marker` is the resting band
 * (width 0) and `.marker-on` draws it, wiping in over 280ms.
 */

.marker {
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  background-image: linear-gradient(var(--marker-ink), var(--marker-ink));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 0.42em;
  transition: background-size 280ms var(--ease-settle);
}

.marker-on {
  background-size: 100% 0.42em;
}

@media (prefers-reduced-motion: reduce) {
  .marker {
    transition: none;
  }
}

/*
 * The two marks inside generated prose. <ins> and <u> are something true about the person: the
 * marker band and bold. <b> and <strong> are a title they already know: bold only (titles are
 * frequent, and a band on each would mark nothing). This is the only place the two are styled:
 * add `.marker-prose` to the element that holds the prose.
 */

.marker-prose :is(ins, u) {
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  background-image: linear-gradient(var(--marker-ink), var(--marker-ink));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 0.42em;
  font-weight: 700;
  /* The band is the underline. */
  text-decoration: none;
}

.marker-prose :is(b, strong) {
  background-image: none;
  font-weight: 700;
  text-decoration: none;
}

/* -------------------------------------------------------------- avatar --- */
/*
 * Avatar.md. A round picture, 32px, on the neutral control wash; no border, no shadow. The image
 * fills the disc (`aspect-square size-full object-cover`), with no padding of its own.
 */

.avatar {
  position: relative;
  display: flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 2rem; /* size-8 */
  height: 2rem;
  overflow: hidden;
  border-radius: var(--radius-full);
  background-color: var(--surface-control);
  color: var(--fg-secondary);
  /* AvatarFallback: text-label */
  font-family: var(--type-family-display);
  font-size: var(--type-label-size);
  line-height: var(--type-label-line-height);
  font-weight: var(--type-label-weight);
}

.avatar > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ----------------------------------------------------------- separator --- */
/* Separator.md. A one-pixel rule where a group ends. Use it instead of <hr> or a border-top div. */

.separator {
  display: block;
  flex-shrink: 0;
  width: 100%;
  height: 1px;
  margin: 0;
  border: 0;
  background-color: var(--border-hairline);
}

.separator--vertical {
  width: 1px;
  height: 100%;
}

/* ------------------------------------------------------------- spinner --- */
/*
 * Spinner.md. A 16px ring that spins, for a wait of unknown length. Put it in the control that
 * started the wait with `data-icon="inline-start"`, and disable the control. It takes the colour of
 * its text (currentColor). Markup: <svg class="spinner" role="status" aria-label="Loading"
 * viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path
 * d="M21 12a9 9 0 1 1-6.219-8.56"/></svg>. Under reduced motion it stays a still ring.
 */

.spinner {
  width: 1rem;
  height: 1rem;
  flex-shrink: 0;
  animation: spinner-spin 1s linear infinite;
}

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

@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation: none;
  }
}

/* ---------------------------------------------------- overlay surfaces --- */
/*
 * Dialog.md and Sheet.md (tasteray-mvp design/components/). An overlay is one step above a card:
 * --popover, never --card or --background. `.overlay-surface` is that step alone, for a page that IS
 * the inside of an overlay whose frame is drawn elsewhere (the widget's chat page: widget.js draws
 * the frame on the merchant's page). `.dialog` is the whole Dialog surface, for an overlay a page
 * draws itself: the step, the control edge, `rounded-xl` and `shadow-2xl`. A card inside either takes
 * the ground (.card .card, above). Padding, gap and width are the caller's layout; the surface is
 * never recoloured, restyled or re-shadowed from a page's own CSS.
 */

.overlay-surface,
.dialog {
  background-color: var(--popover);
  color: var(--popover-foreground);
}

.dialog {
  border: 1px solid var(--border-control);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-2xl);
}

/* --------------------------------------------------------- popup scrim --- */
/* The dim behind a modal: black at 60%, no blur (DESIGN.md § 6). Every overlay uses this. */

.popup-scrim {
  background-color: rgb(0 0 0 / 0.6);
}
