@studiolxd/brand 40.1.0 → 41.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,101 @@ El paquete sigue [semver](https://semver.org/lang/es/): **patch** para bug fixes
7
7
  regeneración de `dist`, **minor** para componentes/props/variantes/tokens nuevos, **major**
8
8
  para breaking changes.
9
9
 
10
+ ## [41.1.0] — 2026-09-15
11
+
12
+ > **Minor.** El interruptor de la barra de filtros se centra con el campo que tiene al
13
+ > lado, el pie de una tarjeta cumple la norma de las acciones por sí solo, y `block` queda
14
+ > escrito como lo que es: la excepción.
15
+
16
+ ### `FilterBar`: un control sin rótulo, a la altura del que sí lo lleva
17
+
18
+ Un interruptor no lleva rótulo encima y un campo sí, así que en la rejilla el interruptor
19
+ se pegaba arriba, a la altura de los **rótulos** en vez de a la de los **campos**. Ahora la
20
+ barra le reserva a esa celda el renglón del rótulo —medido por token, no a ojo— y, en el
21
+ espacio que queda, abre una caja de **la altura de un campo** y centra el control dentro.
22
+
23
+ Medido en Chromium: los centros de la caja del campo, del interruptor y del botón de las
24
+ acciones caen en el mismo píxel. La referencia es la **talla estándar del campo**, no el
25
+ alto real del renglón, y eso es lo que permite tener las dos cosas a la vez: un control que
26
+ crece hacia abajo —un selector múltiple con fichas— sigue creciendo sin mover a nadie, y
27
+ los rótulos siguen todos en su línea. Donde ningún filtro lleva rótulo no se reserva nada,
28
+ y apilado, por debajo del punto de ruptura, tampoco.
29
+
30
+ ### `CardFooter` cumple la norma solo
31
+
32
+ Era la única ranura de acciones del sistema que no lo hacía: siempre una fila, con la
33
+ columna a pedir a mano — la prop de escape que la norma vino a quitar, mudada del botón al
34
+ contenedor. Ahora, por debajo de `md`, sus acciones ocupan la línea como en las otras once
35
+ ranuras.
36
+
37
+ `direction="column"` **se queda**, y con un significado más limpio: ya no es «acuérdate de
38
+ apilar en móvil», sino «apila **siempre**, también donde hay sitio» — el pie con una línea
39
+ de texto sobre el botón, o la tarjeta que se sabe estrecha en escritorio.
40
+
41
+ **Por qué por ventana y no por contenedor**, que es el hallazgo que merece quedar escrito:
42
+ se intentó como el pie de un diálogo y se midió antes de darlo por bueno. Declarar la
43
+ tarjeta como contenedor (`container-type: inline-size`) le quita el ancho que saca de su
44
+ contenido: dos tarjetas dentro de un `Inline` pasan de medir lo que mide su texto a 34px,
45
+ solo su propio aire. **Una tarjeta no puede ser contenedor** porque se usa de las dos
46
+ maneras —unas veces la estira su hueco, otras la mide su contenido—; un diálogo sí, porque
47
+ su ancho siempre viene de fuera. Queda en `Foundations › Puntos de ruptura` como el primer
48
+ límite documentado de la técnica.
49
+
50
+ ### `Button.block`, escrito al derecho
51
+
52
+ Su documentación decía que era «lo que quiere un botón suelto dentro de una página», que es
53
+ justo la invitación a usarlo en vez de buscar la ranura. Ahora dice lo contrario, y la
54
+ norma tiene su mitad negativa escrita:
55
+
56
+ > Todo botón vive en una ranura de acciones. Si no hay ranura que le encaje, eso es un
57
+ > hueco del sistema que se reporta — no un `block` que se añade.
58
+
59
+ Con la lista de las ranuras que dan la línea entera y de las que no la dan a propósito
60
+ —las que viven dentro de una fila, donde estirar rompería la fila que les da sentido—.
61
+ `AnnotationThread` sale de la lista de dudosos: vive en un panel estrecho también en
62
+ escritorio, así que sus acciones ocupan la línea **siempre**, sin punto de ruptura.
63
+
64
+ ## [41.0.0] — 2026-09-15
65
+
66
+ > **Major.** Segunda familia al proveedor de textos: `Table` y `DataTable` pierden sus
67
+ > textos castellano por defecto.
68
+
69
+ ### Las tablas leen del proveedor
70
+
71
+ Mismo mecanismo que estrenó `Pagination` en la v40.0.0 y mismo orden —**prop → proveedor →
72
+ error**—, ahora en la familia que más superficie ocupa en una aplicación. `BrandMessages`
73
+ gana dos espacios:
74
+
75
+ - **`table`** — `actions`, `sortable`, `sortedAscending`, `sortedDescending`.
76
+ - **`dataTable`** — `empty`, `search`.
77
+
78
+ Los cinco calcan clave a clave el catálogo de la suite, así que montarlos es mapear y no
79
+ traducir de nuevo. Es incompatible **en tiempo de compilación**, que es justo lo que se
80
+ busca: el contrato exige los dos espacios, así que ninguna aplicación compila hasta
81
+ añadirlos — nadie se entera en producción de que le falta un texto.
82
+
83
+ ### Lo que NO se fue al proveedor, y por qué
84
+
85
+ La distinción que gobierna toda la campaña: al catálogo común va lo que el componente emite
86
+ **por su cuenta** e igual en toda la suite; se queda como prop lo que es **contenido de esa
87
+ pantalla**.
88
+
89
+ - `Table.caption` y `TableRow.label` nombran ESA tabla y ESA fila.
90
+ - `DataTable.ariaLabel` nombra ESA lista.
91
+ - `DataTable.emptyMessage` **sobrevive como anulación**: el catálogo pone el aviso genérico,
92
+ y la prop queda para el que explica algo del dominio —«todavía no has invitado a nadie»—.
93
+ No es una concesión: en la suite ya hay pantallas que dan un vacío distinto según haya
94
+ filtros o no, y eso ningún catálogo común puede saberlo.
95
+
96
+ `DataTable.searchClearLabel` se queda como **reenvío puro**: ese texto no lo emite la tabla,
97
+ lo emite el `InputField` que lleva dentro, y ese átomo todavía no está migrado.
98
+
99
+ ### Lo que esta ola enseña sobre las que vienen
100
+
101
+ Una familia no queda limpia del todo mientras reenvíe texto a un componente sin migrar, y
102
+ eso **no se ve desde dentro de la familia**. De ahí que las olas siguientes se ordenen para
103
+ que los átomos de formulario caigan pronto: medio catálogo termina reenviando a ellos.
104
+
10
105
  ## [40.1.0] — 2026-09-15
11
106
 
12
107
  > **Minor.** `AnnotationThread` gana un tercer estado y una ranura para la coordenada de
@@ -2539,6 +2539,8 @@ var e = {
2539
2539
  "--filter-bar-row-gap": "0.75rem",
2540
2540
  "--filter-bar-column-min-inline-size": "12rem",
2541
2541
  "--filter-bar-actions-gap": "0.75rem",
2542
+ "--filter-bar-label-offset": "calc(0.875rem * 1.5 + 0.5rem)",
2543
+ "--filter-bar-control-block-size": "2.5rem",
2542
2544
  "--form-field-gap": "0.25rem",
2543
2545
  "--image-crop-dialog-gap": "1rem",
2544
2546
  "--image-crop-dialog-area-max-height": "60vh",
@@ -3093,6 +3095,7 @@ var e = {
3093
3095
  "--annotation-thread-item-gap": "0.5rem",
3094
3096
  "--annotation-thread-items-gap": "1rem",
3095
3097
  "--annotation-thread-header-gap": "0.5rem",
3098
+ "--annotation-thread-actions-gap": "0.75rem",
3096
3099
  "--annotation-thread-author-font-family": "\"Google Sans Flex\", system-ui, sans-serif",
3097
3100
  "--annotation-thread-author-font-size": "0.875rem",
3098
3101
  "--annotation-thread-author-font-weight": "500",
@@ -28,10 +28,23 @@ export interface ButtonBaseProps extends Omit<React.ComponentPropsWithoutRef<'bu
28
28
  /** Size of the button */
29
29
  size?: 'sm' | 'md' | 'lg';
30
30
  /**
31
- * Estira el botón hasta el ancho de su contenedor. `'mobile'` lo hace solo
32
- * por debajo de `md`: es lo que quiere un botón suelto dentro de una página
33
- * —una acción que en escritorio se lee bien con su ancho natural y en una
34
- * pantalla estrecha queda mejor ocupando la línea entera.
31
+ * Estira el botón hasta el ancho de su contenedor (`'mobile'`, solo por
32
+ * debajo de `md`). **Es la excepción marcada, no el camino normal.**
33
+ *
34
+ * Todo botón vive en una **ranura de acciones**: el pie de un `Form` o de un
35
+ * diálogo, las `actions` de un `Alert`, de una `FilterBar`, de un `Hero`, de
36
+ * un `PageIntro`… Y el ancho lo decide la ranura, no el botón: la norma del
37
+ * sistema (Fundamentos › **Puntos de ruptura**) hace que en móvil las
38
+ * acciones tomen la línea entera desde el CSS del contenedor, sin prop que
39
+ * acordarse de pasar. Dentro de una ranura del sistema `block` no hace falta,
40
+ * y pasarlo es pelearse con ella.
41
+ *
42
+ * **Si no hay ranura que le encaje, eso es un hueco del sistema y se
43
+ * reporta** — no un `block` que se añade.
44
+ *
45
+ * Queda, entonces, para el botón que de verdad NO está en una ranura de
46
+ * acciones: la llamada a la acción dentro de un texto, o la fila que un
47
+ * producto monta a mano mientras el sistema no tiene su ranura.
35
48
  */
36
49
  block?: boolean | 'mobile';
37
50
  /**
@@ -1,4 +1,6 @@
1
1
  import type { PaginationMessages } from '../molecules/Pagination/Pagination';
2
+ import type { TableMessages } from '../molecules/Table/Table';
3
+ import type { DataTableMessages } from '../organisms/DataTable/DataTable';
2
4
  /**
3
5
  * El contrato de textos de la librería: un espacio por componente, y dentro
4
6
  * de cada espacio **todas las claves obligatorias**.
@@ -22,5 +24,7 @@ import type { PaginationMessages } from '../molecules/Pagination/Pagination';
22
24
  */
23
25
  export interface BrandMessages {
24
26
  pagination: PaginationMessages;
27
+ table: TableMessages;
28
+ dataTable: DataTableMessages;
25
29
  }
26
- export type { PaginationMessages };
30
+ export type { PaginationMessages, TableMessages, DataTableMessages };
@@ -2,4 +2,4 @@ export { BrandMessagesProvider } from './BrandMessagesProvider';
2
2
  export type { BrandMessagesProviderProps } from './BrandMessagesProvider';
3
3
  export { useBrandMessages } from './BrandMessagesContext';
4
4
  export type { BrandMessagesReader } from './BrandMessagesContext';
5
- export type { BrandMessages, PaginationMessages } from './BrandMessages';
5
+ export type { BrandMessages, PaginationMessages, TableMessages, DataTableMessages, } from './BrandMessages';
@@ -142,11 +142,20 @@ export declare const CardAction: import("react").ForwardRefExoticComponent<Omit<
142
142
  export declare const CardContent: import("react").ForwardRefExoticComponent<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
143
143
  export interface CardFooterProps extends CardPartProps {
144
144
  /**
145
- * `row` (por defecto): las acciones en fila. `column`: apiladas y a todo
146
- * el ancho — para un pie con una línea de texto sobre el botón (una nota
147
- * de prueba, una condición) que debe quedar pegada a él.
145
+ * `row` (por defecto): las acciones en fila **en escritorio**; por debajo de
146
+ * `md` apilan y ocupan la línea entera solas, que es la norma del sistema
147
+ * (Fundamentos › Puntos de ruptura) — no hay que pedirlo.
148
+ *
149
+ * `column`: apiladas y a todo el ancho **siempre, también donde hay sitio**.
150
+ * Es la excepción declarada, para un pie con una línea de texto sobre el
151
+ * botón (una nota de prueba, una condición) que debe quedar pegada a él, y
152
+ * para una tarjeta que se sabe estrecha en escritorio —una rejilla de tres
153
+ * columnas—, porque el pie mide su hueco y no la ventana.
148
154
  */
149
155
  direction?: 'row' | 'column';
150
156
  }
151
- /** Pie de la tarjeta: sus acciones, en fila o apiladas. */
157
+ /**
158
+ * Pie de la tarjeta: sus acciones. En móvil apila y da la línea entera a cada
159
+ * una; en escritorio, fila —salvo `direction="column"`—.
160
+ */
152
161
  export declare const CardFooter: import("react").ForwardRefExoticComponent<CardFooterProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -1,5 +1,25 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import './Table.css';
3
+ /**
4
+ * Los textos que la tabla emite por su cuenta: el cromo de la cabecera —el
5
+ * estado de ordenación y el rótulo de la columna de acciones—, igual en toda
6
+ * la suite. Los nombres calcan el espacio `table` del catálogo, así que
7
+ * montarlo es mapear clave a clave y no traducir de nuevo.
8
+ *
9
+ * Lo que NO está aquí es deliberado: el `caption` de una tabla y el `label`
10
+ * de una fila son contenido de ESA pantalla, no cromo del componente, y
11
+ * siguen siendo props sin valor por defecto.
12
+ */
13
+ export interface TableMessages {
14
+ /** Rótulo oculto de la cabecera de la columna de acciones. */
15
+ actions: string;
16
+ /** Texto oculto de una columna ordenable que todavía no ordena. */
17
+ sortable: string;
18
+ /** Texto oculto de la columna ordenada de forma ascendente. */
19
+ sortedAscending: string;
20
+ /** Texto oculto de la columna ordenada de forma descendente. */
21
+ sortedDescending: string;
22
+ }
3
23
  export interface TableProps extends React.TableHTMLAttributes<HTMLTableElement> {
4
24
  /**
5
25
  * Texto de `<caption>` (se oculta visualmente). **Opcional**: sin `caption` no se
@@ -19,7 +39,10 @@ export interface TableHeaderProps extends React.ThHTMLAttributes<HTMLTableCellEl
19
39
  onSort?: () => void;
20
40
  /** Marca esta columna como columna de acciones: ancho mínimo y cabecera oculta visualmente */
21
41
  actions?: boolean;
22
- /** Texto accesible de la cabecera de acciones. Default: «Acciones» (castellano). Una app multiidioma debe pasarlo traducido. */
42
+ /**
43
+ * Texto accesible de la cabecera de acciones. Sin default: cuando no se
44
+ * pasa, sale de `table.actions` del `BrandMessagesProvider`.
45
+ */
23
46
  actionsLabel?: string;
24
47
  /**
25
48
  * Pega la columna al borde final (`inset-inline-end: 0`) cuando la tabla
@@ -29,13 +52,13 @@ export interface TableHeaderProps extends React.ThHTMLAttributes<HTMLTableCellEl
29
52
  */
30
53
  sticky?: 'end';
31
54
  /**
32
- * Texto accesible del estado de ordenación ascendente. Default: "Ordenado ascendente"
33
- * (castellano). Una app multiidioma debe pasarlo traducido.
55
+ * Texto accesible del estado de ordenación ascendente. Sin default:
56
+ * `table.sortedAscending`.
34
57
  */
35
58
  sortedAscLabel?: string;
36
- /** Texto accesible del estado descendente. Default: «Ordenado descendente» (castellano). Una app multiidioma debe pasarlo traducido. */
59
+ /** Texto accesible del estado descendente. Sin default: `table.sortedDescending`. */
37
60
  sortedDescLabel?: string;
38
- /** Texto accesible de la columna ordenable sin ordenar. Default: «Activar ordenación» (castellano). Una app multiidioma debe pasarlo traducido. */
61
+ /** Texto accesible de la columna ordenable sin ordenar. Sin default: `table.sortable`. */
39
62
  sortableLabel?: string;
40
63
  /**
41
64
  * Impide que el rótulo de esta columna se parta en dos líneas. Mismo valor
@@ -55,8 +78,8 @@ export interface TableRowProps extends Omit<React.HTMLAttributes<HTMLTableRowEle
55
78
  /**
56
79
  * Nombre accesible de la fila. Por defecto el rol `row` toma su nombre del
57
80
  * contenido de sus celdas; pásalo solo cuando ese texto no identifique la
58
- * fila (celdas de solo iconos, datos crípticos). Default: castellano — no
59
- * hay texto por defecto, es el consumidor quien lo escribe.
81
+ * fila (celdas de solo iconos, datos crípticos). No sale del catálogo
82
+ * común: identifica a ESTA fila, así que lo escribe el consumidor.
60
83
  */
61
84
  label?: string;
62
85
  children: ReactNode;
@@ -43,7 +43,16 @@ export interface AnnotationThreadProps extends React.ComponentPropsWithoutRef<'a
43
43
  * `resolved` se retira visualmente sin desaparecer.
44
44
  */
45
45
  status?: AnnotationThreadStatus;
46
- /** Acciones del hilo entero: resolver, reabrir, seguir. Van al pie. */
46
+ /**
47
+ * Acciones del hilo entero: resolver, reabrir, seguir. Van al pie, **una por
48
+ * línea y a la línea entera**, siempre: el hilo vive en un panel de revisión
49
+ * —una columna estrecha también en escritorio—, así que el ancho de la
50
+ * ventana no dice nada de lo que mide este hueco.
51
+ *
52
+ * Se pasan sueltas (`<><Button/><Button/></>`), sin envolverlas en un
53
+ * `Inline`: el envoltorio se llevaría la línea y los botones se quedarían a
54
+ * su ancho natural dentro de él.
55
+ */
47
56
  actions?: ReactNode;
48
57
  /** Con qué se responde: un `MessageComposer`, un `TextareaField`, un `Button`. */
49
58
  reply?: ReactNode;
@@ -3,6 +3,18 @@ import { type ColumnDef, type RowData } from '@tanstack/react-table';
3
3
  import { type PaginationProps } from '../../molecules/Pagination/Pagination';
4
4
  import { type TableHeaderProps } from '../../molecules/Table/Table';
5
5
  import './DataTable.css';
6
+ /**
7
+ * Los textos que la tabla de datos emite por su cuenta. Son dos, y los dos son
8
+ * cromo: el rótulo del buscador y el aviso de que no hay filas. El resto de su
9
+ * texto o llega por props de contenido (`ariaLabel`) o lo ponen sus piezas
10
+ * (`Table`, `Pagination`), cada una desde su propio espacio.
11
+ */
12
+ export interface DataTableMessages {
13
+ /** Aviso del estado vacío cuando no hay filas que pintar. */
14
+ empty: string;
15
+ /** Rótulo —oculto a la vista— y placeholder del buscador. */
16
+ search: string;
17
+ }
6
18
  /** Alineación del contenido de una columna. `start` es el default. */
7
19
  export type DataTableAlign = 'start' | 'center' | 'end';
8
20
  declare module '@tanstack/react-table' {
@@ -66,9 +78,15 @@ export interface DataTableProps<TData, TValue> {
66
78
  value: string;
67
79
  onChange: (value: string) => void;
68
80
  };
69
- /** Placeholder y nombre accesible del buscador. */
81
+ /**
82
+ * Placeholder y nombre accesible del buscador. Sin default: cuando no se
83
+ * pasa, sale de `dataTable.search` del `BrandMessagesProvider`.
84
+ */
70
85
  searchPlaceholder?: string;
71
- /** Nombre accesible del botón que vacía el buscador. Default castellano. */
86
+ /**
87
+ * Nombre accesible del botón que vacía el buscador. `DataTable` no le pone
88
+ * ninguno: sin esta prop manda el de `InputField`.
89
+ */
72
90
  searchClearLabel?: string;
73
91
  /** Se renderiza a la derecha del buscador. */
74
92
  toolbar?: ReactNode;
@@ -81,7 +99,11 @@ export interface DataTableProps<TData, TValue> {
81
99
  footerActions?: ReactNode;
82
100
  /** Filas por página cuando la tabla pagina en cliente. */
83
101
  pageSize?: number;
84
- /** Texto del estado vacío. */
102
+ /**
103
+ * Texto del estado vacío. Sin default: sale de `dataTable.empty`. Pásalo
104
+ * cuando esta pantalla tenga algo propio que decir («Aún no has invitado a
105
+ * nadie»), que un catálogo común no puede saber.
106
+ */
85
107
  emptyMessage?: string;
86
108
  isLoading?: boolean;
87
109
  pagination?: DataTableServerPagination;
@@ -94,8 +116,8 @@ export interface DataTableProps<TData, TValue> {
94
116
  * paginación (en cliente o en servidor) sobre el `Table` y el `Pagination` del
95
117
  * DS. El comportamiento lo aporta TanStack Table.
96
118
  *
97
- * Los textos accesibles llegan por props (el DS no habla de i18n): los de
98
- * `Table` caen a sus castellanos por defecto, y los de `Pagination` —que ya no
99
- * tiene ninguno— al `BrandMessagesProvider` que la aplicación monta en su raíz.
119
+ * Ningún texto viene puesto: los propios salen del espacio `dataTable` del
120
+ * `BrandMessagesProvider`, y los de sus piezas de los suyos (`table`,
121
+ * `pagination`). Las props de texto siguen ahí como anulación puntual.
100
122
  */
101
123
  export declare function DataTable<TData, TValue>({ columns, data, ariaLabel, ariaLabelledBy, searchColumnId, search, searchPlaceholder, searchClearLabel, toolbar, footerActions, pageSize, emptyMessage, isLoading, pagination, headerLabels, paginationLabels, className, }: DataTableProps<TData, TValue>): import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- .annotation-thread{gap:var(--annotation-thread-gap);padding-block:var(--annotation-thread-padding-block);padding-inline:var(--annotation-thread-padding-inline);border:var(--annotation-thread-border-width) var(--annotation-thread-border-style) var(--annotation-thread-border-color);flex-direction:column;display:flex}.annotation-thread.annotation-thread--acknowledged{opacity:var(--annotation-thread-acknowledged-opacity)}.annotation-thread.annotation-thread--resolved{opacity:var(--annotation-thread-resolved-opacity)}.annotation-thread__status{display:flex}.annotation-thread__item{gap:var(--annotation-thread-item-gap);flex-direction:column;display:flex}.annotation-thread__header{align-items:center;gap:var(--annotation-thread-header-gap);flex-wrap:wrap;display:flex}.annotation-thread__avatar{flex-shrink:0;display:inline-flex}.annotation-thread__author{font-family:var(--annotation-thread-author-font-family);font-size:var(--annotation-thread-author-font-size);font-weight:var(--annotation-thread-author-font-weight);color:var(--annotation-thread-author-color)}.annotation-thread__date,.annotation-thread__edited{font-size:var(--annotation-thread-meta-font-size);color:var(--annotation-thread-meta-color)}.annotation-thread__meta{align-items:center;gap:var(--annotation-thread-header-gap);overflow-wrap:anywhere;min-inline-size:0;font-size:var(--annotation-thread-meta-font-size);color:var(--annotation-thread-meta-color);flex-wrap:wrap;display:inline-flex}.annotation-thread__body{font-size:var(--annotation-thread-body-font-size);line-height:var(--annotation-thread-body-line-height);color:var(--annotation-thread-body-color)}.annotation-thread__item-actions{gap:var(--annotation-thread-header-gap);flex-wrap:wrap;display:flex}.annotation-thread__replies{gap:var(--annotation-thread-items-gap);border-inline-start:var(--annotation-thread-reply-guide-width) var(--annotation-thread-reply-guide-style) var(--annotation-thread-reply-guide-color);flex-direction:column;padding-inline-start:var(--annotation-thread-reply-indent);display:flex}.annotation-thread__replies-label{font-size:var(--annotation-thread-replies-label-font-size);color:var(--annotation-thread-replies-label-color);margin-block:0}.annotation-thread__actions{gap:var(--annotation-thread-header-gap);flex-wrap:wrap;display:flex}
1
+ .annotation-thread{gap:var(--annotation-thread-gap);padding-block:var(--annotation-thread-padding-block);padding-inline:var(--annotation-thread-padding-inline);border:var(--annotation-thread-border-width) var(--annotation-thread-border-style) var(--annotation-thread-border-color);flex-direction:column;display:flex}.annotation-thread.annotation-thread--acknowledged{opacity:var(--annotation-thread-acknowledged-opacity)}.annotation-thread.annotation-thread--resolved{opacity:var(--annotation-thread-resolved-opacity)}.annotation-thread__status{display:flex}.annotation-thread__item{gap:var(--annotation-thread-item-gap);flex-direction:column;display:flex}.annotation-thread__header{align-items:center;gap:var(--annotation-thread-header-gap);flex-wrap:wrap;display:flex}.annotation-thread__avatar{flex-shrink:0;display:inline-flex}.annotation-thread__author{font-family:var(--annotation-thread-author-font-family);font-size:var(--annotation-thread-author-font-size);font-weight:var(--annotation-thread-author-font-weight);color:var(--annotation-thread-author-color)}.annotation-thread__date,.annotation-thread__edited{font-size:var(--annotation-thread-meta-font-size);color:var(--annotation-thread-meta-color)}.annotation-thread__meta{align-items:center;gap:var(--annotation-thread-header-gap);overflow-wrap:anywhere;min-inline-size:0;font-size:var(--annotation-thread-meta-font-size);color:var(--annotation-thread-meta-color);flex-wrap:wrap;display:inline-flex}.annotation-thread__body{font-size:var(--annotation-thread-body-font-size);line-height:var(--annotation-thread-body-line-height);color:var(--annotation-thread-body-color)}.annotation-thread__item-actions{gap:var(--annotation-thread-header-gap);flex-wrap:wrap;display:flex}.annotation-thread__replies{gap:var(--annotation-thread-items-gap);border-inline-start:var(--annotation-thread-reply-guide-width) var(--annotation-thread-reply-guide-style) var(--annotation-thread-reply-guide-color);flex-direction:column;padding-inline-start:var(--annotation-thread-reply-indent);display:flex}.annotation-thread__replies-label{font-size:var(--annotation-thread-replies-label-font-size);color:var(--annotation-thread-replies-label-color);margin-block:0}.annotation-thread__actions{align-items:stretch;gap:var(--annotation-thread-actions-gap);flex-direction:column;display:flex}.annotation-thread__actions>*{inline-size:100%}