rte-utils 1.2.28 → 1.2.30

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/README.md CHANGED
@@ -15,23 +15,23 @@ npm install rte-utils
15
15
  You need to import both the component and its CSS styles:
16
16
 
17
17
  ```tsx
18
- import { Histogram, Chip } from "rte-utils";
19
- import "rte-utils/dist/index.css"; // Import the CSS styles
18
+ import { Histogram, Chip } from 'rte-utils';
19
+ import 'rte-utils/dist/index.css'; // Import the CSS styles
20
20
  ```
21
21
 
22
22
  ### Basic Example
23
23
 
24
24
  ```tsx
25
- import React from "react";
26
- import { Histogram } from "rte-utils";
27
- import "rte-utils/dist/index.css";
25
+ import React from 'react';
26
+ import { Histogram } from 'rte-utils';
27
+ import 'rte-utils/dist/index.css';
28
28
 
29
29
  function App() {
30
30
  return (
31
31
  <div>
32
32
  <Histogram
33
- max={{ value: 100, color: "#D3D64E" }}
34
- relative={{ value: 56, color: "#C0C402" }}
33
+ max={{ value: 100, color: '#D3D64E' }}
34
+ relative={{ value: 56, color: '#C0C402' }}
35
35
  barWidth={32}
36
36
  >
37
37
  <div className="histogram-value-container">
@@ -52,18 +52,18 @@ export default App;
52
52
  ### Advanced Example with Animation
53
53
 
54
54
  ```tsx
55
- import React, { useState } from "react";
56
- import { Histogram } from "rte-utils";
57
- import "rte-utils/dist/index.css";
55
+ import React, { useState } from 'react';
56
+ import { Histogram } from 'rte-utils';
57
+ import 'rte-utils/dist/index.css';
58
58
 
59
59
  function EnergyDashboard() {
60
60
  const [currentValue, setCurrentValue] = useState(45);
61
61
 
62
62
  return (
63
- <div style={{ display: "flex", gap: "1rem" }}>
63
+ <div style={{ display: 'flex', gap: '1rem' }}>
64
64
  <Histogram
65
- max={{ value: 100, color: "#D3D64E" }}
66
- relative={{ value: currentValue, color: "#C0C402" }}
65
+ max={{ value: 100, color: '#D3D64E' }}
66
+ relative={{ value: currentValue, color: '#C0C402' }}
67
67
  barHeight={120}
68
68
  barWidth={40}
69
69
  >
@@ -76,9 +76,7 @@ function EnergyDashboard() {
76
76
  </div>
77
77
  </Histogram>
78
78
 
79
- <button onClick={() => setCurrentValue((prev) => prev + 10)}>
80
- Increase (+10)
81
- </button>
79
+ <button onClick={() => setCurrentValue((prev) => prev + 10)}>Increase (+10)</button>
82
80
  </div>
83
81
  );
84
82
  }
@@ -87,16 +85,16 @@ function EnergyDashboard() {
87
85
  ### Horizontal Orientation Example
88
86
 
89
87
  ```tsx
90
- import React from "react";
91
- import { Histogram } from "rte-utils";
92
- import "rte-utils/dist/index.css";
88
+ import React from 'react';
89
+ import { Histogram } from 'rte-utils';
90
+ import 'rte-utils/dist/index.css';
93
91
 
94
92
  function HorizontalChart() {
95
93
  return (
96
- <div style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
94
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
97
95
  <Histogram
98
- max={{ value: 100, color: "#D3D64E" }}
99
- relative={{ value: 75, color: "#C0C402" }}
96
+ max={{ value: 100, color: '#D3D64E' }}
97
+ relative={{ value: 75, color: '#C0C402' }}
100
98
  barWidth={200} // This becomes height in horizontal mode
101
99
  barHeight={24} // This becomes width in horizontal mode
102
100
  orientation="horizontal"
@@ -117,17 +115,17 @@ function HorizontalChart() {
117
115
  ### Custom Corner Radius Example
118
116
 
119
117
  ```tsx
120
- import React from "react";
121
- import { Histogram } from "rte-utils";
122
- import "rte-utils/dist/index.css";
118
+ import React from 'react';
119
+ import { Histogram } from 'rte-utils';
120
+ import 'rte-utils/dist/index.css';
123
121
 
124
122
  function CustomCornerChart() {
125
123
  return (
126
- <div style={{ display: "flex", gap: "1rem" }}>
124
+ <div style={{ display: 'flex', gap: '1rem' }}>
127
125
  {/* Rounded top corners only */}
128
126
  <Histogram
129
- max={{ value: 100, color: "#E0E0E0" }}
130
- relative={{ value: 60, color: "#4CAF50" }}
127
+ max={{ value: 100, color: '#E0E0E0' }}
128
+ relative={{ value: 60, color: '#4CAF50' }}
131
129
  barWidth={32}
132
130
  barHeight={120}
133
131
  cornerRadius={{
@@ -140,8 +138,8 @@ function CustomCornerChart() {
140
138
 
141
139
  {/* Fully rounded corners */}
142
140
  <Histogram
143
- max={{ value: 100, color: "#F0F0F0", opacity: 0.5 }}
144
- relative={{ value: 80, color: "#2196F3" }}
141
+ max={{ value: 100, color: '#F0F0F0', opacity: 0.5 }}
142
+ relative={{ value: 80, color: '#2196F3' }}
145
143
  barWidth={32}
146
144
  barHeight={120}
147
145
  cornerRadius={{
@@ -154,8 +152,8 @@ function CustomCornerChart() {
154
152
 
155
153
  {/* Asymmetric corners */}
156
154
  <Histogram
157
- max={{ value: 100, color: "#FFECB3" }}
158
- relative={{ value: 45, color: "#FF9800" }}
155
+ max={{ value: 100, color: '#FFECB3' }}
156
+ relative={{ value: 45, color: '#FF9800' }}
159
157
  barWidth={32}
160
158
  barHeight={120}
161
159
  cornerRadius={{
@@ -173,15 +171,15 @@ function CustomCornerChart() {
173
171
  ### Opacity and Advanced Styling Example
174
172
 
175
173
  ```tsx
176
- import React from "react";
177
- import { Histogram } from "rte-utils";
178
- import "rte-utils/dist/index.css";
174
+ import React from 'react';
175
+ import { Histogram } from 'rte-utils';
176
+ import 'rte-utils/dist/index.css';
179
177
 
180
178
  function AdvancedStylingChart() {
181
179
  return (
182
180
  <Histogram
183
- max={{ value: 100, color: "#000000", opacity: 0.1 }}
184
- relative={{ value: 65, color: "#E91E63" }}
181
+ max={{ value: 100, color: '#000000', opacity: 0.1 }}
182
+ relative={{ value: 65, color: '#E91E63' }}
185
183
  barWidth={40}
186
184
  barHeight={150}
187
185
  orientation="vertical"
@@ -235,9 +233,26 @@ A histogram component with smooth animations for energy data visualization.
235
233
  The component uses external CSS classes for styling. Make sure to import the CSS file:
236
234
 
237
235
  ```tsx
238
- import "rte-utils/dist/index.css";
236
+ import 'rte-utils/dist/index.css';
239
237
  ```
240
238
 
239
+ ## Scripts
240
+
241
+ Development & quality commands:
242
+
243
+ - `npm run build` – build the library (Rollup)
244
+ - `npm run dev` – watch mode build
245
+ - `npm run test` – run tests
246
+ - `npm run lint` – run ESLint (no fixes)
247
+ - `npm run lint:fix` – run ESLint with auto fixes
248
+ - `npm run format` – apply Prettier formatting
249
+ - `npm run format:check` – check formatting (CI)
250
+ - `npm run typecheck` – TypeScript diagnostics (no emit)
251
+ - `npm run storybook` – start Storybook
252
+ - `npm run build-storybook` – build static Storybook
253
+
254
+ Prettier is integrated with ESLint (plugin:prettier/recommended). Formatting issues will surface as ESLint errors.
255
+
241
256
  You can override the default styles by targeting the CSS classes:
242
257
 
243
258
  - `.histogram-container` - Main container
@@ -259,35 +274,35 @@ A comprehensive production unit component that combines an image display, status
259
274
 
260
275
  #### Props
261
276
 
262
- | Prop | Type | Required | Default | Description |
263
- | ---------------- | ------------------------- | -------- | -------------------- | -------------------------------------------------- |
264
- | `onChangeInput` | `(value: number) => void` | ❌ | - | Callback triggered when input value changes |
265
- | `onChangeSwitch` | `(checked: boolean) => void` | ❌ | - | Callback triggered when switch state changes |
266
- | `defaultValue` | `number` | ❌ | - | Initial value for the input field |
267
- | `defaultChecked` | `boolean` | ❌ | `false` | Initial state for the switch |
268
- | `unitName` | `string` | ❌ | `"Production Unit"` | Display name for the production unit |
269
- | `energyCost` | `number` | ❌ | `0` | Energy cost value displayed in the chip (MW) |
270
- | `checkedImage` | `React.ReactNode` | ❌ | - | Custom image/component displayed when switch is ON |
271
- | `uncheckedImage` | `React.ReactNode` | ❌ | - | Custom image/component displayed when switch is OFF |
277
+ | Prop | Type | Required | Default | Description |
278
+ | ---------------- | ---------------------------- | -------- | ------------------- | --------------------------------------------------- |
279
+ | `onChangeInput` | `(value: number) => void` | ❌ | - | Callback triggered when input value changes |
280
+ | `onChangeSwitch` | `(checked: boolean) => void` | ❌ | - | Callback triggered when switch state changes |
281
+ | `defaultValue` | `number` | ❌ | - | Initial value for the input field |
282
+ | `defaultChecked` | `boolean` | ❌ | `false` | Initial state for the switch |
283
+ | `unitName` | `string` | ❌ | `"Production Unit"` | Display name for the production unit |
284
+ | `energyCost` | `number` | ❌ | `0` | Energy cost value displayed in the chip (MW) |
285
+ | `checkedImage` | `React.ReactNode` | ❌ | - | Custom image/component displayed when switch is ON |
286
+ | `uncheckedImage` | `React.ReactNode` | ❌ | - | Custom image/component displayed when switch is OFF |
272
287
 
273
288
  #### Example Usage
274
289
 
275
290
  ```tsx
276
- import React from "react";
277
- import { ProductionUnit } from "rte-utils";
278
- import "rte-utils/dist/index.css";
291
+ import React from 'react';
292
+ import { ProductionUnit } from 'rte-utils';
293
+ import 'rte-utils/dist/index.css';
279
294
 
280
295
  function ProductionUnitExample() {
281
296
  const handleInputChange = (value: number) => {
282
- console.log("Production value changed:", value);
297
+ console.log('Production value changed:', value);
283
298
  };
284
299
 
285
300
  const handleSwitchChange = (checked: boolean) => {
286
- console.log("Production unit is now:", checked ? "ON" : "OFF");
301
+ console.log('Production unit is now:', checked ? 'ON' : 'OFF');
287
302
  };
288
303
 
289
304
  return (
290
- <div style={{ display: "flex", gap: "1rem", flexWrap: "wrap" }}>
305
+ <div style={{ display: 'flex', gap: '1rem', flexWrap: 'wrap' }}>
291
306
  {/* Basic usage */}
292
307
  <ProductionUnit
293
308
  unitName="Solar Panel"
@@ -305,16 +320,10 @@ function ProductionUnitExample() {
305
320
  defaultChecked={false}
306
321
  defaultValue={75}
307
322
  checkedImage={
308
- <img
309
- src="https://placehold.co/60x60/4CAF50/FFFFFF/png?text=ON"
310
- alt="Wind Turbine On"
311
- />
323
+ <img src="https://placehold.co/60x60/4CAF50/FFFFFF/png?text=ON" alt="Wind Turbine On" />
312
324
  }
313
325
  uncheckedImage={
314
- <img
315
- src="https://placehold.co/60x60/F44336/FFFFFF/png?text=OFF"
316
- alt="Wind Turbine Off"
317
- />
326
+ <img src="https://placehold.co/60x60/F44336/FFFFFF/png?text=OFF" alt="Wind Turbine Off" />
318
327
  }
319
328
  onChangeInput={handleInputChange}
320
329
  onChangeSwitch={handleSwitchChange}
@@ -326,32 +335,36 @@ function ProductionUnitExample() {
326
335
  energyCost={1000}
327
336
  defaultChecked={true}
328
337
  checkedImage={
329
- <div style={{
330
- width: 60,
331
- height: 60,
332
- borderRadius: '50%',
333
- backgroundColor: '#4CAF50',
334
- display: 'flex',
335
- alignItems: 'center',
336
- justifyContent: 'center',
337
- color: 'white',
338
- fontWeight: 'bold'
339
- }}>
338
+ <div
339
+ style={{
340
+ width: 60,
341
+ height: 60,
342
+ borderRadius: '50%',
343
+ backgroundColor: '#4CAF50',
344
+ display: 'flex',
345
+ alignItems: 'center',
346
+ justifyContent: 'center',
347
+ color: 'white',
348
+ fontWeight: 'bold',
349
+ }}
350
+ >
340
351
 
341
352
  </div>
342
353
  }
343
354
  uncheckedImage={
344
- <div style={{
345
- width: 60,
346
- height: 60,
347
- borderRadius: '50%',
348
- backgroundColor: '#F44336',
349
- display: 'flex',
350
- alignItems: 'center',
351
- justifyContent: 'center',
352
- color: 'white',
353
- fontWeight: 'bold'
354
- }}>
355
+ <div
356
+ style={{
357
+ width: 60,
358
+ height: 60,
359
+ borderRadius: '50%',
360
+ backgroundColor: '#F44336',
361
+ display: 'flex',
362
+ alignItems: 'center',
363
+ justifyContent: 'center',
364
+ color: 'white',
365
+ fontWeight: 'bold',
366
+ }}
367
+ >
355
368
  ⚠️
356
369
  </div>
357
370
  }
@@ -393,13 +406,13 @@ A customizable chip component for displaying labels, tags, or status indicators.
393
406
  #### Example Usage
394
407
 
395
408
  ```tsx
396
- import React from "react";
397
- import { Chip } from "rte-utils";
398
- import "rte-utils/dist/index.css";
409
+ import React from 'react';
410
+ import { Chip } from 'rte-utils';
411
+ import 'rte-utils/dist/index.css';
399
412
 
400
413
  function ChipExample() {
401
414
  return (
402
- <div style={{ display: "flex", gap: "0.5rem" }}>
415
+ <div style={{ display: 'flex', gap: '0.5rem' }}>
403
416
  {/* Default chip */}
404
417
  <Chip label="Default" />
405
418
 
@@ -1,5 +1,5 @@
1
- import React from "react";
2
- import "./Avatar.css";
1
+ import React from 'react';
2
+ import './Avatar.css';
3
3
  interface AvatarProps {
4
4
  children: React.ReactNode;
5
5
  }
@@ -1,5 +1,5 @@
1
- import type { Meta, StoryObj } from "@storybook/react";
2
- import { Avatar } from "./Avatar";
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Avatar } from './Avatar';
3
3
  declare const meta: Meta<typeof Avatar>;
4
4
  export default meta;
5
5
  type Story = StoryObj<typeof meta>;
@@ -1,9 +1,9 @@
1
- import React from "react";
2
- import "./Chip.css";
1
+ import React from 'react';
2
+ import './Chip.css';
3
3
  interface ChipProps {
4
4
  children: React.ReactNode;
5
5
  bgColor?: string;
6
- width?: "fit-content" | "full-width";
6
+ width?: 'fit-content' | 'full-width';
7
7
  }
8
8
  export declare const Chip: React.FC<ChipProps>;
9
9
  export {};
@@ -1,5 +1,5 @@
1
- import type { Meta, StoryObj } from "@storybook/react";
2
- import { Chip } from "./Chip";
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Chip } from './Chip';
3
3
  declare const meta: Meta<typeof Chip>;
4
4
  export default meta;
5
5
  type Story = StoryObj<typeof meta>;
@@ -1,5 +1,5 @@
1
- import React from "react";
2
- import "./Histogram.css";
1
+ import React from 'react';
2
+ import './Histogram.css';
3
3
  interface HistogramProps {
4
4
  /** Maximum value configuration with value and color */
5
5
  max: {
@@ -1,5 +1,5 @@
1
- import type { Meta, StoryObj } from "@storybook/react";
2
- import { Histogram } from "./Histogram";
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Histogram } from './Histogram';
3
3
  declare const meta: Meta<typeof Histogram>;
4
4
  export default meta;
5
5
  type Story = StoryObj<typeof meta>;
@@ -0,0 +1,22 @@
1
+ import React from "react";
2
+ import "./Histogramme.css";
3
+ interface HistogramProps {
4
+ /** Maximum value configuration with value and color */
5
+ max: {
6
+ value: number;
7
+ color: string;
8
+ };
9
+ /** Relative/current value configuration with value and color */
10
+ relative: {
11
+ value: number;
12
+ color: string;
13
+ };
14
+ /** Height of the histogram bar in pixels */
15
+ barHeight?: number;
16
+ /** Width of the histogram bar in pixels */
17
+ barWidth?: number;
18
+ /** Child components (typically text content) */
19
+ children?: React.ReactNode;
20
+ }
21
+ export declare const Histogram: React.FC<HistogramProps>;
22
+ export {};
@@ -1,5 +1,5 @@
1
- import React from "react";
2
- import "./Input.css";
1
+ import React from 'react';
2
+ import './Input.css';
3
3
  interface InputNumberProps {
4
4
  label: string;
5
5
  value?: string;
@@ -1,5 +1,5 @@
1
- import React from "react";
2
- import "./InputNumber.css";
1
+ import React from 'react';
2
+ import './InputNumber.css';
3
3
  interface InputNumberProps {
4
4
  label: string;
5
5
  value?: string;
@@ -1,5 +1,5 @@
1
- import type { Meta, StoryObj } from "@storybook/react";
2
- import { InputNumber } from "./InputNumber";
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { InputNumber } from './InputNumber';
3
3
  declare const meta: Meta<typeof InputNumber>;
4
4
  export default meta;
5
5
  type Story = StoryObj<typeof meta>;
@@ -1,5 +1,5 @@
1
- import React from "react";
2
- import "./MwhCost.css";
1
+ import React from 'react';
2
+ import './MwhCost.css';
3
3
  interface MwhCostProps {
4
4
  cost?: number;
5
5
  textColor?: string;
@@ -1,4 +1,4 @@
1
- import "./ProductionUnit.css";
1
+ import './ProductionUnit.css';
2
2
  type ProductionUnitLimit = {
3
3
  value: number;
4
4
  label?: string;
@@ -1,5 +1,5 @@
1
- import type { Meta, StoryObj } from "@storybook/react";
2
- import { ProductionUnit } from "./ProductionUnit";
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { ProductionUnit } from './ProductionUnit';
3
3
  declare const meta: Meta<typeof ProductionUnit>;
4
4
  export default meta;
5
5
  type Story = StoryObj<typeof meta>;
@@ -1,4 +1,4 @@
1
- import "./ProductionUnitContainer.css";
1
+ import './ProductionUnitContainer.css';
2
2
  interface ProductionUnitContainerProps {
3
3
  bgColor?: string;
4
4
  children: React.ReactNode;
@@ -1,5 +1,5 @@
1
- import type { Meta, StoryObj } from "@storybook/react";
2
- import { ProductionUnitContainer } from "./ProductionUnitContainer";
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { ProductionUnitContainer } from './ProductionUnitContainer';
3
3
  declare const meta: Meta<typeof ProductionUnitContainer>;
4
4
  export default meta;
5
5
  type Story = StoryObj<typeof meta>;
@@ -1,5 +1,5 @@
1
- import React from "react";
2
- import "./Switch.css";
1
+ import React from 'react';
2
+ import './Switch.css';
3
3
  interface SwitchProps {
4
4
  checked?: boolean;
5
5
  onChange?: (checked: boolean) => void;
@@ -1,5 +1,5 @@
1
- import type { Meta, StoryObj } from "@storybook/react";
2
- import { Switch } from "./Switch";
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Switch } from './Switch';
3
3
  declare const meta: Meta<typeof Switch>;
4
4
  export default meta;
5
5
  type Story = StoryObj<typeof meta>;
@@ -0,0 +1,43 @@
1
+ import React from 'react';
2
+ import './Timer.css';
3
+ export interface TimerProps {
4
+ phases: {
5
+ duration: number;
6
+ title?: string;
7
+ }[];
8
+ onComplete?: () => void;
9
+ onPhaseComplete?: (phaseIndex: number, phaseDuration: number) => void;
10
+ onTick?: (currentTime: number, phaseIndex: number) => void;
11
+ onStart?: () => void;
12
+ onPause?: () => void;
13
+ onFreeze?: (frozen: boolean) => void;
14
+ onAnonymiseToggle?: (anonymised: boolean) => void;
15
+ onStop?: () => void;
16
+ onReset?: () => void;
17
+ onPrevious?: () => void;
18
+ onNext?: () => void;
19
+ onPhaseClick?: (phaseIndex: number) => void;
20
+ autoStart?: boolean;
21
+ className?: string;
22
+ gameActions?: {
23
+ [phaseIndex: number]: string;
24
+ };
25
+ user?: 'actor' | 'admin';
26
+ }
27
+ export interface TimerRef {
28
+ start: () => void;
29
+ pause: () => void;
30
+ freeze: (force?: boolean) => void;
31
+ toggleAnonymise: (force?: boolean) => void;
32
+ stop: () => void;
33
+ reset: () => void;
34
+ setPhases: (phases: {
35
+ duration: number;
36
+ title?: string;
37
+ }[]) => void;
38
+ getCurrentTime: () => number;
39
+ getCurrentPhase: () => number;
40
+ isRunning: () => boolean;
41
+ isPaused: () => boolean;
42
+ }
43
+ export declare const Timer: React.ForwardRefExoticComponent<TimerProps & React.RefAttributes<TimerRef>>;
@@ -0,0 +1,17 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Timer } from './Timer';
3
+ declare const meta: Meta<typeof Timer>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof meta>;
6
+ export declare const Default: Story;
7
+ export declare const GameTimer: Story;
8
+ export declare const SinglePhase: Story;
9
+ export declare const MinimalTimer: Story;
10
+ export declare const ProgressOnly: Story;
11
+ export declare const WithPhaseTitles: Story;
12
+ export declare const WithCallbacks: Story;
13
+ export declare const ControlledTimer: Story;
14
+ export declare const FreezeDemo: Story;
15
+ export declare const AdminUser: Story;
16
+ export declare const ActorUser: Story;
17
+ export declare const UserComparison: Story;
@@ -1,8 +1,10 @@
1
- export { ProductionUnit } from "./ProductionUnit";
2
- export { ProductionUnitContainer } from "./ProductionUnitContainer";
3
- export { Histogram } from "./Histogram";
4
- export { Chip } from "./Chip";
5
- export { Switch } from "./Switch";
6
- export { InputNumber } from "./InputNumber";
7
- export { Avatar } from "./Avatar";
8
- export { MwhCost } from "./MwhCost";
1
+ export { ProductionUnit } from './ProductionUnit';
2
+ export { ProductionUnitContainer } from './ProductionUnitContainer';
3
+ export { Histogram } from './Histogram';
4
+ export { Chip } from './Chip';
5
+ export { Switch } from './Switch';
6
+ export { InputNumber } from './InputNumber';
7
+ export { Avatar } from './Avatar';
8
+ export { MwhCost } from './MwhCost';
9
+ export { Timer } from './Timer';
10
+ export type { TimerProps, TimerRef } from './Timer';
package/dist/index.css CHANGED
@@ -1 +1 @@
1
- .input-container,.input-field{position:relative;width:100%}.input-element{background-color:#fff;border:2px solid #e0e0e0;border-radius:4px;box-sizing:border-box;font-size:16px;outline:none;padding:8px 0 8px 12px;transition:border-color .2s ease,box-shadow .2s ease;width:100%}.input-element:focus{border-color:#009cdf;box-shadow:0 0 0 2px rgba(0,156,223,.1)}.input-label{background-color:#fff;color:#999;font-size:16px;left:12px;padding:0 4px;pointer-events:none;position:absolute;top:50%;transform:translateY(-50%);transition:all .2s ease;white-space:nowrap}.input-required{color:#e74c3c;margin-left:2px}.input-container--floating .input-label,.input-container--focused .input-label{font-size:12px;font-weight:500;top:0;transform:translateY(-50%)}.input-container--focused .input-element{border-color:#009cdf;box-shadow:0 0 0 2px rgba(0,156,223,.1)}.input-container--focused .input-label{color:#009cdf}.input-container--error .input-element{border-color:#e74c3c}.input-container--error .input-element:focus{border-color:#e74c3c;box-shadow:0 0 0 2px rgba(231,76,60,.1)}.input-container--error .input-label,.input-error{color:#e74c3c}.input-error{font-size:12px;margin-top:4px;padding-left:12px}.input-container--disabled .input-element{background-color:#f5f5f5;border-color:#d0d0d0;color:#999;cursor:not-allowed}.input-container--disabled .input-label{color:#999}.input-element:not(:disabled):hover{border-color:#009cdf}.input-container--error .input-element:not(:disabled):hover{border-color:#e74c3c}.input-element:-webkit-autofill{-webkit-text-fill-color:inherit!important}.input-element:-webkit-autofill,.input-element:-webkit-autofill:focus{-webkit-box-shadow:inset 0 0 0 30px #fff!important}.input-container--small .input-element{font-size:14px;padding:12px 8px 6px}.input-container--small .input-label{font-size:14px;left:8px}.input-container--small.input-container--floating .input-label,.input-container--small.input-container--focused .input-label{font-size:10px}.input-container--large .input-element{font-size:18px;padding:20px 16px 10px}.input-container--large .input-label{font-size:18px;left:16px}.input-container--large.input-container--floating .input-label,.input-container--large.input-container--focused .input-label{font-size:14px}.input-constraints{align-items:center;display:flex;gap:8px;justify-content:space-between}.input-max,.input-min{color:#999;font-size:12px;text-align:center}.input-container--focused .input-max,.input-container--focused .input-min{color:#009cdf;font-weight:500}.input-element[type=number]::-webkit-inner-spin-button,.input-element[type=number]::-webkit-outer-spin-button{-webkit-appearance:auto;cursor:pointer;margin:0;opacity:1}.input-element[type=number]{-moz-appearance:textfield}.input-element[type=number]:hover::-webkit-inner-spin-button,.input-element[type=number]:hover::-webkit-outer-spin-button{opacity:1}.switch-container{align-items:center;display:flex;gap:8px}.switch-wrapper{align-items:center;display:flex;flex-direction:column;gap:4px}.switch-icon{height:16px;width:16px}.switch-icon,.switch-label{align-items:center;display:flex;justify-content:center}.switch-label{color:#666;font-size:12px;font-weight:500;min-height:16px;padding:0 2px}.switch-power-icon{height:100%;object-fit:contain;width:100%}.switch{background:none;border:none;cursor:pointer;outline:none;padding:0;transition:all .2s ease}.switch:focus-visible{outline:2px solid #009cdf;outline-offset:2px}.switch--disabled{cursor:not-allowed;opacity:.5}.switch-track{background-color:#999fa1;border-radius:60px;display:block;position:relative;transition:background-color .2s ease}.switch--checked .switch-track{background-color:#82d4f6}.switch-wrapper--checked .switch-label{color:#82d4f6}.switch-thumb{align-items:center;background-color:#fff;border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.2);display:flex;justify-content:center;left:0;position:absolute;top:-3px;transition:transform .2s ease}.switch-thumb-icon{height:100%;object-fit:contain;width:100%}.switch-track{height:10px;width:32px}.switch-thumb{height:16px;width:16px}.switch--checked .switch-thumb{transform:translateX(16px)}.switch:not(.switch--disabled):hover .switch-track{filter:brightness(1.1)}.switch:not(.switch--disabled):active .switch-thumb{transform:scale(1.1)}.switch--checked:not(.switch--disabled):active .switch-thumb{transform:translateX(16px) scale(1.1)}.switch--small.switch--checked:not(.switch--disabled):active .switch-thumb{transform:translateX(12px) scale(1.1)}.switch--large.switch--checked:not(.switch--disabled):active .switch-thumb{transform:translateX(20px) scale(1.1)}.production-unit-container{align-items:center;display:flex;height:64px;justify-content:space-between;padding-right:24px}.production-unit-content{align-items:center;display:flex;gap:16px}.production-unit-chip{display:flex;flex-direction:column;flex-shrink:0}.production-unit-chip-name{word-wrap:break-word;color:#11161a;font-size:16px;font-weight:600;line-height:24px}.production-unit-switch-container{width:156px}.chip-container{align-items:center;background-color:var(--chip-bg-color,#e0e0e0);border-radius:60px;color:var(--chip-text-color,#000);display:inline-flex;min-width:84px;padding:4px 8px}.chip-container--fit-content{width:fit-content}.chip-container--full-width{width:100%}.chip-content{align-items:center;display:flex;flex-grow:1;gap:.5rem;justify-content:center}.chip-label{font-size:14px;font-weight:600;margin:0}.production-unit-container-box{border-radius:64px;box-shadow:0 2px 16px 0 rgba(0,0,0,.16);box-sizing:border-box;width:100%}@import url("https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600&display=swap");*{font-family:Open Sans,sans-serif}.histogram-container{height:auto;max-width:54px;position:relative}.histogram-container--horizontal{max-width:none;width:auto}.histogram-content{align-items:center;display:flex;flex-direction:column;gap:8px;width:100%}.histogram-content--horizontal{align-items:center;flex-direction:row;height:100%}.histogram-bar{position:relative}.histogram-svg{display:block}.histogram-text-container{align-items:center;display:flex;flex-direction:column;gap:0;justify-content:center;width:100%}.histogram-text-container--horizontal{align-items:flex-start;margin-left:8px}.histogram-value-container{text-align:center;width:40px}.histogram-value{font-size:16px;line-height:14px}.histogram-unit,.histogram-value{color:#000;display:block;font-weight:600;margin:0}.histogram-unit{font-size:12px}.histogram-label{color:#6f6f6f;font-size:12px;font-style:normal;font-weight:400;line-height:18px;margin:0;text-align:left;white-space:nowrap}.avatar-container{align-items:center;border:1px solid #f5f3ed;border-radius:50%;color:#333;display:inline-flex;font-size:20px;font-weight:500;height:64px;justify-content:center;overflow:hidden;position:relative;user-select:none;width:64px}.avatar-container--clickable{cursor:pointer;transition:transform .2s ease,box-shadow .2s ease}.avatar-container--clickable:hover{box-shadow:0 2px 8px rgba(0,0,0,.15);transform:scale(1.05)}.avatar-container--clickable:active{transform:scale(.95)}.avatar-content{align-items:center;display:flex;height:100%;justify-content:center;width:100%}.avatar-content img{height:100%;object-fit:cover;width:100%}.avatar-content{line-height:1;text-transform:uppercase}.cost-text-container{align-items:baseline;display:flex;gap:3px}.cost-number{font-size:16px;font-weight:semibold}.cost-unit{font-size:16px;line-height:24px}.cost-unit-per{font-size:12px;font-weight:400;letter-spacing:0;line-height:18px;text-transform:uppercase}
1
+ .input-container,.input-field{position:relative;width:100%}.input-element{background-color:#fff;border:2px solid #e0e0e0;border-radius:4px;box-sizing:border-box;font-size:16px;outline:none;padding:8px 0 8px 12px;transition:border-color .2s ease,box-shadow .2s ease;width:100%}.input-element:focus{border-color:#009cdf;box-shadow:0 0 0 2px rgba(0,156,223,.1)}.input-label{background-color:#fff;color:#999;font-size:16px;left:12px;padding:0 4px;pointer-events:none;position:absolute;top:50%;transform:translateY(-50%);transition:all .2s ease;white-space:nowrap}.input-required{color:#e74c3c;margin-left:2px}.input-container--floating .input-label,.input-container--focused .input-label{font-size:12px;font-weight:500;top:0;transform:translateY(-50%)}.input-container--focused .input-element{border-color:#009cdf;box-shadow:0 0 0 2px rgba(0,156,223,.1)}.input-container--focused .input-label{color:#009cdf}.input-container--error .input-element{border-color:#e74c3c}.input-container--error .input-element:focus{border-color:#e74c3c;box-shadow:0 0 0 2px rgba(231,76,60,.1)}.input-container--error .input-label,.input-error{color:#e74c3c}.input-error{font-size:12px;margin-top:4px;padding-left:12px}.input-container--disabled .input-element{background-color:#f5f5f5;border-color:#d0d0d0;color:#999;cursor:not-allowed}.input-container--disabled .input-label{color:#999}.input-element:not(:disabled):hover{border-color:#009cdf}.input-container--error .input-element:not(:disabled):hover{border-color:#e74c3c}.input-element:-webkit-autofill{-webkit-text-fill-color:inherit!important}.input-element:-webkit-autofill,.input-element:-webkit-autofill:focus{-webkit-box-shadow:inset 0 0 0 30px #fff!important}.input-container--small .input-element{font-size:14px;padding:12px 8px 6px}.input-container--small .input-label{font-size:14px;left:8px}.input-container--small.input-container--floating .input-label,.input-container--small.input-container--focused .input-label{font-size:10px}.input-container--large .input-element{font-size:18px;padding:20px 16px 10px}.input-container--large .input-label{font-size:18px;left:16px}.input-container--large.input-container--floating .input-label,.input-container--large.input-container--focused .input-label{font-size:14px}.input-constraints{align-items:center;display:flex;gap:8px;justify-content:space-between}.input-max,.input-min{color:#999;font-size:12px;text-align:center}.input-container--focused .input-max,.input-container--focused .input-min{color:#009cdf;font-weight:500}.input-element[type=number]::-webkit-inner-spin-button,.input-element[type=number]::-webkit-outer-spin-button{-webkit-appearance:auto;cursor:pointer;margin:0;opacity:1}.input-element[type=number]{-moz-appearance:textfield}.input-element[type=number]:hover::-webkit-inner-spin-button,.input-element[type=number]:hover::-webkit-outer-spin-button{opacity:1}.switch-container{align-items:center;display:flex;gap:8px}.switch-wrapper{align-items:center;display:flex;flex-direction:column;gap:4px}.switch-icon{height:16px;width:16px}.switch-icon,.switch-label{align-items:center;display:flex;justify-content:center}.switch-label{color:#666;font-size:12px;font-weight:500;min-height:16px;padding:0 2px}.switch-power-icon{height:100%;object-fit:contain;width:100%}.switch{background:none;border:none;cursor:pointer;outline:none;padding:0;transition:all .2s ease}.switch:focus-visible{outline:2px solid #009cdf;outline-offset:2px}.switch--disabled{cursor:not-allowed;opacity:.5}.switch-track{background-color:#999fa1;border-radius:60px;display:block;position:relative;transition:background-color .2s ease}.switch--checked .switch-track{background-color:#82d4f6}.switch-wrapper--checked .switch-label{color:#82d4f6}.switch-thumb{align-items:center;background-color:#fff;border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.2);display:flex;justify-content:center;left:0;position:absolute;top:-3px;transition:transform .2s ease}.switch-thumb-icon{height:100%;object-fit:contain;width:100%}.switch-track{height:10px;width:32px}.switch-thumb{height:16px;width:16px}.switch--checked .switch-thumb{transform:translateX(16px)}.switch:not(.switch--disabled):hover .switch-track{filter:brightness(1.1)}.switch:not(.switch--disabled):active .switch-thumb{transform:scale(1.1)}.switch--checked:not(.switch--disabled):active .switch-thumb{transform:translateX(16px) scale(1.1)}.switch--small.switch--checked:not(.switch--disabled):active .switch-thumb{transform:translateX(12px) scale(1.1)}.switch--large.switch--checked:not(.switch--disabled):active .switch-thumb{transform:translateX(20px) scale(1.1)}.production-unit-container{align-items:center;display:flex;height:64px;justify-content:space-between;padding-right:24px}.production-unit-content{align-items:center;display:flex;gap:16px}.production-unit-chip{display:flex;flex-direction:column;flex-shrink:0}.production-unit-chip-name{word-wrap:break-word;color:#11161a;font-size:16px;font-weight:600;line-height:24px}.production-unit-switch-container{width:156px}.chip-container{align-items:center;background-color:var(--chip-bg-color,#e0e0e0);border-radius:60px;color:var(--chip-text-color,#000);display:inline-flex;min-width:84px;padding:4px 8px}.chip-container--fit-content{width:fit-content}.chip-container--full-width{width:100%}.chip-content{align-items:center;display:flex;flex-grow:1;gap:.5rem;justify-content:center}.chip-label{font-size:14px;font-weight:600;margin:0}.production-unit-container-box{border-radius:64px;box-shadow:0 2px 16px 0 rgba(0,0,0,.16);box-sizing:border-box;width:100%}@import url("https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600&display=swap");*{font-family:Open Sans,sans-serif}.histogram-container{height:auto;max-width:54px;position:relative}.histogram-container--horizontal{max-width:none;width:auto}.histogram-content{align-items:center;display:flex;flex-direction:column;gap:8px;width:100%}.histogram-content--horizontal{align-items:center;flex-direction:row;height:100%}.histogram-bar{position:relative}.histogram-svg{display:block}.histogram-text-container{align-items:center;display:flex;flex-direction:column;gap:0;justify-content:center;width:100%}.histogram-text-container--horizontal{align-items:flex-start;margin-left:8px}.histogram-value-container{text-align:center;width:40px}.histogram-value{font-size:16px;line-height:14px}.histogram-unit,.histogram-value{color:#000;display:block;font-weight:600;margin:0}.histogram-unit{font-size:12px}.histogram-label{color:#6f6f6f;font-size:12px;font-style:normal;font-weight:400;line-height:18px;margin:0;text-align:left;white-space:nowrap}.avatar-container{align-items:center;border:1px solid #f5f3ed;border-radius:50%;color:#333;display:inline-flex;font-size:20px;font-weight:500;height:64px;justify-content:center;overflow:hidden;position:relative;user-select:none;width:64px}.avatar-container--clickable{cursor:pointer;transition:transform .2s ease,box-shadow .2s ease}.avatar-container--clickable:hover{box-shadow:0 2px 8px rgba(0,0,0,.15);transform:scale(1.05)}.avatar-container--clickable:active{transform:scale(.95)}.avatar-content{align-items:center;display:flex;height:100%;justify-content:center;width:100%}.avatar-content img{height:100%;object-fit:cover;width:100%}.avatar-content{line-height:1;text-transform:uppercase}.cost-text-container{align-items:baseline;display:flex;gap:3px}.cost-number{font-size:16px;font-weight:semibold}.cost-unit{font-size:16px;line-height:24px}.cost-unit-per{font-size:12px;font-weight:400;letter-spacing:0;line-height:18px;text-transform:uppercase}.timer-header-control{border:1px solid red;box-sizing:border-box;display:flex;font-family:Open Sans,sans-serif;width:100%}.timer-section{background-color:#fff;border-bottom-left-radius:16px;border-top-left-radius:16px;display:flex;flex-shrink:0;padding:10px 0 10px 16px}.timer-content{align-items:center;display:flex;gap:8px;padding-right:8px}.timer-display-area{display:flex;flex-direction:column;flex-shrink:0;gap:10px}.timer-header{align-items:baseline;color:#11161a;display:flex;justify-content:space-between;width:124px}.timer-title{flex-shrink:0;font-size:12px;font-weight:700;line-height:12px;min-width:64px;text-align:left;text-transform:uppercase}.timer-time,.timer-title{font-family:Open Sans,sans-serif}.timer-time{font-size:20px;font-weight:600;line-height:14px;text-align:right;white-space:nowrap;width:61px}.timer-progress-bar{background:#000;border-radius:4px;height:8px;overflow:hidden;position:relative;width:124px}.timer-progress-fill{background:#009cdf;border-radius:4px;height:100%;transition:width .3s ease}.step-indicators{align-items:center;display:flex;gap:4px}.step-indicator{align-items:center;border-radius:50%;color:#fff;display:flex;flex-shrink:0;font-family:Open Sans,sans-serif;font-size:12px;font-weight:600;height:16px;justify-content:center;line-height:18px;width:16px}.step-indicator--active{background-color:#009cdf}.step-indicator--active.step-indicator--actor{height:40px;margin-right:4px;width:40px}.step-indicator--active.step-indicator--admin{height:16px;width:16px}.step-indicator--completed{background-color:#005896}.step-indicator--upcoming{background-color:#b7bec2}.step-expand{align-items:center;background-color:#292e33;border-radius:50%;color:#fff;display:flex;justify-content:center;margin-left:4px;transform:rotate(90deg)}.timer-controls-section{align-items:center;align-self:stretch;background-color:#fff;display:flex;flex-shrink:0;gap:10px;padding:10px 16px 10px 10px}.control-button{align-items:center;background:none;background:#d9d9d9;border:none;cursor:pointer;display:flex;height:24px;justify-content:center;padding:0;position:relative;width:24px}.control-button,.control-button:before{border-radius:50%;height:32px;width:32px}.control-button:before{background:radial-gradient(circle,rgba(0,0,0,.1) 0,transparent 70%);content:"";left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);z-index:-1}.control-button:hover:before{background:radial-gradient(circle,rgba(0,0,0,.15) 0,transparent 70%)}.control-button svg{color:#000;height:16px;width:16px}.timer--running .step-indicator--active{animation:pulse 1s ease-in-out infinite alternate}.timer--frozen .timer-progress-fill{background:#7aa6b9}.control-button--anonymise-active{background-color:#444;color:#fff}.control-button--freeze-active{background:#7aa6b9}.control-button--freeze-active svg path{fill:#000}@keyframes pulse{0%{background-color:#009cdf}to{background-color:#0081b8}}.step-indicator--placeholder{background-color:#e9ecef;color:#6c757d;position:relative}.step-indicator--placeholder:after{content:attr(data-step);font-size:10px;font-weight:700;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%)}.step-expand.step-expand--end{background-color:#1a7f37;transform:none}.timer-header--block{display:flex;flex-direction:column;gap:10px;margin-right:10px}@media (max-width:480px){.timer-header-control{flex-direction:column}.timer-section{border-radius:16px 16px 0 0}.timer-controls-section{border-radius:0 0 16px 16px;justify-content:center}}.step-indicator--clickable{cursor:pointer;position:relative;transition:background-color .2s ease,box-shadow .2s ease,transform .1s ease}.step-indicator--clickable:focus-visible{box-shadow:0 0 0 2px #11161a;outline:2px solid #fff;outline-offset:2px}.step-indicator--clickable:hover{filter:brightness(1.1)}.step-indicator--clickable:active{transform:scale(.9)}.step-indicator--selected{box-shadow:0 0 0 2px #fff,0 0 0 4px #ffb100}