@ntmats/hc-ui 0.8.0 → 0.10.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/README.md +1 -1
- package/dist/index.d.ts +27 -2
- package/dist/index.js +60 -16
- package/dist/styles.css +41 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -95,4 +95,4 @@ Fixed colors that stay the same in both themes are HeroClix tokens: `color-dial-
|
|
|
95
95
|
|
|
96
96
|
`PhysicalCardView` is the printed card in HCUnits' format (375×525 px, absolute positions), scaled to its container's width: front and back side by side while each keeps about 86% of its size, otherwise one under the other, never above 1.2×. With `fitHeight` the front also fits the visible height of the scrolling area found by `fitHeightWithin`. Everything comes resolved: the backgrounds (`images.front`, `images.back`, `images.legacy`, `layout.rarityImage`, `layout.dialImage`: addresses the app serves; HCUI's are in its `public/card/` and do not ship here), the title (its type shrinks from 28px to fit), header lines, team abilities (buttons that open a tip, with the shield the caller passes in `teamAbilityIcon`), the collection number and set symbol, the token (`portrait` drawn by the caller with the class the card gives, `terrain` art or an `object` ring in its color), the bystander's token replica, keyphrases, the rules (already translated, with an optional `icon`; tapping a paragraph calls `onCopy(copyText)`), improved abilities, the printed dial as a node (`dial.node`, usually `CombatDialView` with `presentation="printed"`), the terrain dial, points (buttons that call `onSelectPoint`, an object's line or nothing) and the black back bar. Rules that do not fit the front move to the backs, two columns each, one block at a time (`nextPhysicalCardDistribution`); the split starts over when `contentKey` changes. Under a mouse the card tilts up to 3° toward the pointer, with parallax and a shine (nearly still over the dial); on a phone only the focus view moves, by the motion sensor (`requestPhysicalCardMotionAccess` asks iOS on the first touch). Holding the card with a finger for 450 ms calls `onRequestFocus`; the caller opens `PhysicalCardFocusView` (a modal `<dialog>` over a dimmed, blurred backdrop; Esc and a tap outside, once the opening finger is lifted, call `onClose`) with a second card with `focus`, which shows one side at a time and draws `focusActions({ nextSide, backs, flip })` under it (the library's `Button` `outline` there gets the surface fill). Tips are controlled as in the dial: hover with a mouse opens a passive tip described by the control, a press or Enter opens it as a dialog, leaving closes the passive one; the caller keeps `tip` and draws it in `tipSlot`. Paper, ink, shine and grain follow the theme (`color-card-*`, `filter-card-background`, `blend-card-*`, `opacity-card-grain*`); the printed black and white, the team-up band and the terrain dial are fixed (`color-card-print-*`, `color-card-team-up`, `color-card-terrain-panel*`). Letters are upright (`--hc-rond: 0` on the card, which its printed dial reads too). Motion only with a fine pointer or in the phone's focus view, and none under `prefers-reduced-motion`.
|
|
97
97
|
|
|
98
|
-
`MapBoardView` draws a map already fetched (`map`: the hcmaps JSON, `HCMapJson`) with the hcmaps engine (`HCMap`) in a canvas named by `canvasLabel`, square-cornered and white in both themes (`color-map-board`), and shades the inspected square or draws the inspected edge (`selection`, from `inspectMap`; `color-map-selection*`). `onInspect(x, y, clientX, clientY)` gets the pointer in squares: mouse and pen while passing over, touch on press; `onLeave` when the mouse leaves. Other attributes (role, `tabIndex`, `onKeyDown`, `aria-*`) go to the container, so the caller adds the keyboard (HCUI: arrows move one square, Esc closes). `MapBoardPlaceholder` is the empty grid while it loads, a busy status whose `label` is visually hidden by the library. `MapTooltipView` is fixed next to `anchor` without leaving the screen (portal it out of a clipping container): the title, a wall's color, and for each square (one, or two on an edge) its coordinate, terrain and elevation swatches with the caller's names, the environment (a node, e.g. `MapEnvironmentView`, or `environmentNote`) and notes. `MapSwatch` is the board's square in a legend; `MapLegendView` lists them (the 3D model's legend) with children after; `MapEnvironmentView` shows indoor/outdoor with the caller's icons (black line icons, turned light in the dark theme by `filter-map-environment-icon`) and names. `renderMapThumbnail(json, height)` returns a PNG data URL. The engines are plain functions with no DOM beyond a canvas context: `inspectMap` (square, edge or wall at a point, in squares), `mapSquare`, `mapMaxLevel`, `mapElevationLevel`, `mapSquareCoordinate`; `buildMapScene` (the 3D model's heights, walls, ramps and ziplines), the
|
|
98
|
+
`MapBoardView` draws a map already fetched (`map`: the hcmaps JSON, `HCMapJson`) with the hcmaps engine (`HCMap`) in a canvas named by `canvasLabel`, square-cornered and white in both themes (`color-map-board`), and shades the inspected square or draws the inspected edge (`selection`, from `inspectMap`; `color-map-selection*`). `onInspect(x, y, clientX, clientY)` gets the pointer in squares: mouse and pen while passing over, touch on press; `onLeave` when the mouse leaves. Other attributes (role, `tabIndex`, `onKeyDown`, `aria-*`) go to the container, so the caller adds the keyboard (HCUI: arrows move one square, Esc closes). `MapBoardPlaceholder` is the empty grid while it loads, a busy status whose `label` is visually hidden by the library. `MapTooltipView` is fixed next to `anchor` without leaving the screen (portal it out of a clipping container): the title, a wall's color, and for each square (one, or two on an edge) its coordinate, terrain and elevation swatches with the caller's names, the environment (a node, e.g. `MapEnvironmentView`, or `environmentNote`) and notes. `MapSwatch` is the board's square in a legend; `MapLegendView` lists them (the 3D model's legend) with children after; `MapEnvironmentView` shows indoor/outdoor with the caller's icons (black line icons, turned light in the dark theme by `filter-map-environment-icon`) and names. `renderMapThumbnail(json, height)` returns a PNG data URL. The engines are plain functions with no DOM beyond a canvas context: `inspectMap` (square, edge or wall at a point, in squares), `mapSquare`, `mapMaxLevel`, `mapElevationLevel`, `mapSquareCoordinate`; `buildMapScene` (the 3D model's heights, walls, ramps and ziplines), the camera (`makeMapProjection`, `pickMapScene`, `zoomMapCamera`, `clampMapPan`) and `drawMapScene` (Canvas 2D). The camera is parallel by default; `makeMapProjection(scene, camera, viewport, { perspective: MAP_PERSPECTIVE_DISTANCE })` adds a light perspective (near squares larger, far ones smaller) in the same screen box, with `ground` still exact and `factor(x, y, z)` telling how much a point grew, e.g. to size a figure drawn over the model. `MapBoardView` draws again when the browser gives its canvas back blank (`contextrestored`). The 3D model's component, its gestures and its icons stay in the app.
|
package/dist/index.d.ts
CHANGED
|
@@ -953,9 +953,18 @@ export interface CombatDialViewProps {
|
|
|
953
953
|
/**
|
|
954
954
|
* `comfortable` (default): 40px cells. `compact`: 34px cells, 6px gaps, 13px numbers and
|
|
955
955
|
* tighter point chips, for dense lists (HCUI's compact dial of the unit view on phones).
|
|
956
|
+
* `dense`: 25px cells and rows, 3px between rows, 11–12px numbers, the compact header,
|
|
957
|
+
* for a dial next to other content (the Arena's table card).
|
|
956
958
|
* The printed presentation keeps its own measures.
|
|
957
959
|
*/
|
|
958
|
-
density?: 'comfortable' | 'compact';
|
|
960
|
+
density?: 'comfortable' | 'compact' | 'dense';
|
|
961
|
+
/**
|
|
962
|
+
* How the current click is marked. `bar` (default): a muted column with a thin accent
|
|
963
|
+
* bar on top. `framed`: the column is framed in light gray behind the cells and the click
|
|
964
|
+
* number becomes a filled circle in the text color, easier to find mid-game; the power
|
|
965
|
+
* colors stay intact. Ignored by the printed presentation.
|
|
966
|
+
*/
|
|
967
|
+
currentMark?: 'bar' | 'framed';
|
|
959
968
|
/** Without it the dial is static: it neither marks nor changes the click; only cells with a tip react. */
|
|
960
969
|
onClickChange?: (click: number) => void;
|
|
961
970
|
onSelectPoint: (point: CombatDialPoint) => void;
|
|
@@ -1503,8 +1512,24 @@ export interface MapProjection {
|
|
|
1503
1512
|
depth(x: number, y: number): number;
|
|
1504
1513
|
/** From the screen to the map, on a plane at height `z`. */
|
|
1505
1514
|
ground(px: number, py: number, z: number): [number, number];
|
|
1515
|
+
/**
|
|
1516
|
+
* How much a point at (x, y, z) is enlarged on screen compared with the parallel
|
|
1517
|
+
* projection: above 1 near the camera, below 1 far from it. Always 1 without
|
|
1518
|
+
* `perspective`. Optional so hand-made projections still type-check.
|
|
1519
|
+
*/
|
|
1520
|
+
factor?(x: number, y: number, z: number): number;
|
|
1521
|
+
}
|
|
1522
|
+
export interface MapProjectionOptions {
|
|
1523
|
+
/**
|
|
1524
|
+
* A light perspective, as the camera's distance in half-diagonals of the scene
|
|
1525
|
+
* (`MAP_PERSPECTIVE_DISTANCE` = 4; larger is gentler). Off by default: a parallel
|
|
1526
|
+
* projection, where near and far squares are the same size.
|
|
1527
|
+
*/
|
|
1528
|
+
perspective?: number;
|
|
1506
1529
|
}
|
|
1507
|
-
|
|
1530
|
+
/** The camera distance the Arena's table uses for `perspective`. */
|
|
1531
|
+
export declare const MAP_PERSPECTIVE_DISTANCE = 4;
|
|
1532
|
+
export declare function makeMapProjection(scene: MapScene, camera: MapCamera, viewport: MapViewport, { perspective }?: MapProjectionOptions): MapProjection;
|
|
1508
1533
|
/** The map's center may go as far as any of its corners reaches the middle of the screen. */
|
|
1509
1534
|
export declare function clampMapPan(scene: MapScene, camera: MapCamera, viewport: MapViewport): MapCamera;
|
|
1510
1535
|
/** Zooms keeping the point at `anchor` (measured from the screen's center) still. */
|
package/dist/index.js
CHANGED
|
@@ -1574,6 +1574,7 @@ var CombatDialView = forwardRef(function CombatDialView2({
|
|
|
1574
1574
|
labels,
|
|
1575
1575
|
presentation = "default",
|
|
1576
1576
|
density = "comfortable",
|
|
1577
|
+
currentMark = "bar",
|
|
1577
1578
|
onClickChange,
|
|
1578
1579
|
onSelectPoint,
|
|
1579
1580
|
tip,
|
|
@@ -1677,7 +1678,7 @@ var CombatDialView = forwardRef(function CombatDialView2({
|
|
|
1677
1678
|
COMBAT_DIAL_STATS.map((stat) => /* @__PURE__ */ jsx("div", { className: "hc-ui-combat-dial__cell", "data-kind": "ko", children: labels.koCell }, stat))
|
|
1678
1679
|
] })
|
|
1679
1680
|
] }, rowIndex);
|
|
1680
|
-
return /* @__PURE__ */ jsxs("section", { ref, className: "hc-ui-combat-dial", "data-presentation": presentation, "data-density": density === "
|
|
1681
|
+
return /* @__PURE__ */ jsxs("section", { ref, className: "hc-ui-combat-dial", "data-presentation": presentation, "data-density": density === "comfortable" ? void 0 : density, "data-current-mark": currentMark === "framed" ? "framed" : void 0, "data-static": flag(!tracksClick), children: [
|
|
1681
1682
|
presentation !== "printed" && /* @__PURE__ */ jsxs("header", { className: "hc-ui-combat-dial__header", children: [
|
|
1682
1683
|
/* @__PURE__ */ jsxs("div", { className: "hc-ui-combat-dial__header-top", children: [
|
|
1683
1684
|
/* @__PURE__ */ jsx("span", { className: "hc-ui-combat-dial__label", children: labels.heading }),
|
|
@@ -2757,7 +2758,8 @@ var MAP_DEFAULT_CAMERA = { azimuth: -32, tilt: 52, zoom: 1, panX: 0, panY: 0 };
|
|
|
2757
2758
|
var MAP_TILT_RANGE = [6, 90];
|
|
2758
2759
|
var MAP_ZOOM_RANGE = [1, 6];
|
|
2759
2760
|
var clampMapValue = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
2760
|
-
|
|
2761
|
+
var MAP_PERSPECTIVE_DISTANCE = 4;
|
|
2762
|
+
function makeMapProjection(scene, camera, viewport, { perspective } = {}) {
|
|
2761
2763
|
const rad = camera.azimuth * Math.PI / 180, tilt = camera.tilt * Math.PI / 180;
|
|
2762
2764
|
const sin = Math.sin(rad), cos = Math.cos(rad), sinT = Math.sin(tilt), cosT = Math.cos(tilt);
|
|
2763
2765
|
const cx2 = scene.width / 2, cy = scene.height / 2, midZ = (scene.maxTop + MAP_SCENE_BASE_Z) / 2;
|
|
@@ -2766,7 +2768,7 @@ function makeMapProjection(scene, camera, viewport) {
|
|
|
2766
2768
|
const fit = Math.min(viewport.width / (halfWidth * 2.06), viewport.height / (halfHeight * 2.06));
|
|
2767
2769
|
const scale = fit * camera.zoom;
|
|
2768
2770
|
const ox = viewport.width / 2 + camera.panX, oy = viewport.height / 2 + camera.panY;
|
|
2769
|
-
|
|
2771
|
+
const parallel = {
|
|
2770
2772
|
scale,
|
|
2771
2773
|
sin,
|
|
2772
2774
|
cos,
|
|
@@ -2780,6 +2782,44 @@ function makeMapProjection(scene, camera, viewport) {
|
|
|
2780
2782
|
ground(px, py, z) {
|
|
2781
2783
|
const rx = (px - ox) / scale, ry = ((py - oy) / scale + (z - midZ) * cosT) / sinT;
|
|
2782
2784
|
return [cx2 + rx * cos + ry * sin, cy - rx * sin + ry * cos];
|
|
2785
|
+
},
|
|
2786
|
+
factor: () => 1
|
|
2787
|
+
};
|
|
2788
|
+
if (!perspective || !(perspective > 0)) return parallel;
|
|
2789
|
+
const [sx, sy] = parallel.point(cx2, cy, midZ);
|
|
2790
|
+
const D = perspective * Math.max(1, halfWidth, (scene.maxTop - MAP_SCENE_BASE_Z) / 2);
|
|
2791
|
+
const toward = (x, y, z) => parallel.depth(x, y) * cosT + (z - midZ) * sinT;
|
|
2792
|
+
const raw = (x, y, z) => D / Math.max(D * 0.05, D - toward(x, y, z));
|
|
2793
|
+
const corners = [[0, 0], [scene.width, 0], [scene.width, scene.height], [0, scene.height]];
|
|
2794
|
+
const extremes = corners.flatMap(([x, y]) => [[x, y, scene.maxTop], [x, y, MAP_SCENE_BASE_Z]]);
|
|
2795
|
+
const box = (points) => {
|
|
2796
|
+
const xs = points.map((p) => p[0]), ys = points.map((p) => p[1]);
|
|
2797
|
+
return [Math.max(...xs) - Math.min(...xs), Math.max(...ys) - Math.min(...ys)];
|
|
2798
|
+
};
|
|
2799
|
+
const [flatW, flatH] = box(extremes.map(([x, y, z]) => parallel.point(x, y, z)));
|
|
2800
|
+
const [deepW, deepH] = box(extremes.map(([x, y, z]) => {
|
|
2801
|
+
const [px, py] = parallel.point(x, y, z), f = raw(x, y, z);
|
|
2802
|
+
return [sx + (px - sx) * f, sy + (py - sy) * f];
|
|
2803
|
+
}));
|
|
2804
|
+
const norm = Math.max(flatW > 1e-9 ? deepW / flatW : 0, flatH > 1e-9 ? deepH / flatH : 0) || 1;
|
|
2805
|
+
const factor = (x, y, z) => raw(x, y, z) / norm;
|
|
2806
|
+
return {
|
|
2807
|
+
scale,
|
|
2808
|
+
sin,
|
|
2809
|
+
cos,
|
|
2810
|
+
factor,
|
|
2811
|
+
depth: parallel.depth,
|
|
2812
|
+
point(x, y, z) {
|
|
2813
|
+
const [px, py] = parallel.point(x, y, z), f = factor(x, y, z);
|
|
2814
|
+
return [sx + (px - sx) * f, sy + (py - sy) * f];
|
|
2815
|
+
},
|
|
2816
|
+
ground(px, py, z) {
|
|
2817
|
+
const zc = z - midZ;
|
|
2818
|
+
const v = (py - sy) / scale * norm;
|
|
2819
|
+
const denom = D * sinT + v * cosT;
|
|
2820
|
+
const along = Math.abs(denom) < 1e-9 ? 0 : (v * D - v * zc * sinT + zc * cosT * D) / denom;
|
|
2821
|
+
const f = D / Math.max(D * 0.05, D - along * cosT - zc * sinT) / norm;
|
|
2822
|
+
return parallel.ground(sx + (px - sx) / f, sy + (py - sy) / f, z);
|
|
2783
2823
|
}
|
|
2784
2824
|
};
|
|
2785
2825
|
}
|
|
@@ -2833,11 +2873,9 @@ function pickMapScene(scene, view, px, py) {
|
|
|
2833
2873
|
const p00 = view.point(cell.x, cell.y, cell.top), p10 = view.point(cell.x + 1, cell.y, cell.top);
|
|
2834
2874
|
const p11 = view.point(cell.x + 1, cell.y + 1, cell.top), p01 = view.point(cell.x, cell.y + 1, cell.top);
|
|
2835
2875
|
if (inside(px, py, [p00, p10, p11, p01])) {
|
|
2836
|
-
const
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
const u = ((px - p00[0]) * by - (py - p00[1]) * bx) / det, v = ((py - p00[1]) * ax - (px - p00[0]) * ay) / det;
|
|
2840
|
-
return { x: cell.x + clampMapValue(u, 0, 1), y: cell.y + clampMapValue(v, 0, 1) };
|
|
2876
|
+
const [gx, gy] = view.ground(px, py, cell.top);
|
|
2877
|
+
if (!Number.isFinite(gx) || !Number.isFinite(gy)) return { x: cell.x + 0.5, y: cell.y + 0.5 };
|
|
2878
|
+
return { x: clampMapValue(gx, cell.x, cell.x + 1), y: clampMapValue(gy, cell.y, cell.y + 1) };
|
|
2841
2879
|
}
|
|
2842
2880
|
for (const side of MAP_CELL_SIDES) {
|
|
2843
2881
|
if (side.dx * view.sin + side.dy * view.cos <= 0) continue;
|
|
@@ -3188,14 +3226,19 @@ var MapBoardView = forwardRef(function MapBoardView2({ map, canvasLabel, selecti
|
|
|
3188
3226
|
useEffect(() => {
|
|
3189
3227
|
const canvas = canvasRef.current;
|
|
3190
3228
|
if (!canvas) return;
|
|
3191
|
-
const
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3229
|
+
const draw = () => {
|
|
3230
|
+
const ctx = canvas.getContext("2d");
|
|
3231
|
+
if (!ctx) return;
|
|
3232
|
+
try {
|
|
3233
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
3234
|
+
new HCMap(map).draw(ctx, { grid });
|
|
3235
|
+
} catch {
|
|
3236
|
+
failed.current?.();
|
|
3237
|
+
}
|
|
3238
|
+
};
|
|
3239
|
+
draw();
|
|
3240
|
+
canvas.addEventListener("contextrestored", draw);
|
|
3241
|
+
return () => canvas.removeEventListener("contextrestored", draw);
|
|
3199
3242
|
}, [map, grid]);
|
|
3200
3243
|
function pointer(event) {
|
|
3201
3244
|
const bounds = event.currentTarget.getBoundingClientRect();
|
|
@@ -3306,6 +3349,7 @@ export {
|
|
|
3306
3349
|
MAP_GRID_SOFT_COLOR,
|
|
3307
3350
|
MAP_GRID_TERRAIN_SHADE,
|
|
3308
3351
|
MAP_INDOOR_EDGE_COLOR,
|
|
3352
|
+
MAP_PERSPECTIVE_DISTANCE,
|
|
3309
3353
|
MAP_SCENE_BASE_Z,
|
|
3310
3354
|
MAP_SCENE_LEVEL_HEIGHT,
|
|
3311
3355
|
MAP_TERRAIN_EDGE_COLORS,
|
package/dist/styles.css
CHANGED
|
@@ -1915,6 +1915,47 @@
|
|
|
1915
1915
|
[data-hc-ds] .hc-ui-combat-dial[data-density='compact']:not([data-presentation='printed']) :is(.hc-ui-combat-dial__cell[data-kind='value'], .hc-ui-combat-dial__range) { font-size: var(--hc-font-size-sm); }
|
|
1916
1916
|
[data-hc-ds] .hc-ui-combat-dial[data-density='compact']:not([data-presentation='printed']) .hc-ui-combat-dial__special-icon { width: 18px; height: 18px; }
|
|
1917
1917
|
|
|
1918
|
+
/* `density="dense"`: the compact header (point chips) with 25px cells and rows, 3px between
|
|
1919
|
+
rows and 6px between clicks, 11px click numbers and 12px values, 15px special icons:
|
|
1920
|
+
a dial that sits beside other content (the Arena's table card). */
|
|
1921
|
+
[data-hc-ds] .hc-ui-combat-dial[data-density='dense']:not([data-presentation='printed']) .hc-ui-combat-dial__header { gap: 0; }
|
|
1922
|
+
[data-hc-ds] .hc-ui-combat-dial[data-density='dense']:not([data-presentation='printed']) .hc-ui-combat-dial__points { gap: var(--hc-space-1); padding: var(--hc-space-1) 0; }
|
|
1923
|
+
[data-hc-ds] .hc-ui-combat-dial[data-density='dense']:not([data-presentation='printed']) .hc-ui-combat-dial__chip { gap: var(--hc-space-2); padding: var(--hc-space-2); border-radius: var(--hc-radius-lg); }
|
|
1924
|
+
[data-hc-ds] .hc-ui-combat-dial[data-density='dense']:not([data-presentation='printed']) .hc-ui-combat-dial__grid-wrap { padding: 5px 0; }
|
|
1925
|
+
[data-hc-ds] .hc-ui-combat-dial[data-density='dense']:not([data-presentation='printed']) .hc-ui-combat-dial__grid { gap: 6px; }
|
|
1926
|
+
[data-hc-ds] .hc-ui-combat-dial[data-density='dense']:not([data-presentation='printed']) .hc-ui-combat-dial__col { grid-template-rows: repeat(5, 25px); gap: 3px; }
|
|
1927
|
+
[data-hc-ds] .hc-ui-combat-dial[data-density='dense']:not([data-presentation='printed']) .hc-ui-combat-dial__col[data-start]::before { top: 28px; }
|
|
1928
|
+
[data-hc-ds] .hc-ui-combat-dial[data-density='dense']:not([data-presentation='printed']) .hc-ui-combat-dial__cell { width: 25px; height: 25px; }
|
|
1929
|
+
[data-hc-ds] .hc-ui-combat-dial[data-density='dense']:not([data-presentation='printed']) .hc-ui-combat-dial__cell[data-tip]::after { inset: -2px; }
|
|
1930
|
+
[data-hc-ds] .hc-ui-combat-dial[data-density='dense']:not([data-presentation='printed']) .hc-ui-combat-dial__cell[data-kind='number'] { font-size: 11px; }
|
|
1931
|
+
[data-hc-ds] .hc-ui-combat-dial[data-density='dense']:not([data-presentation='printed']) :is(.hc-ui-combat-dial__cell:is([data-kind='value'], [data-kind='ko']), .hc-ui-combat-dial__range) { font-size: 12px; }
|
|
1932
|
+
[data-hc-ds] .hc-ui-combat-dial[data-density='dense']:not([data-presentation='printed']) .hc-ui-combat-dial__special-icon { width: 15px; height: 15px; }
|
|
1933
|
+
[data-hc-ds] .hc-ui-combat-dial[data-density='dense']:not([data-presentation='printed']) .hc-ui-combat-dial__bolt { height: 11px; }
|
|
1934
|
+
|
|
1935
|
+
/* `currentMark="framed"`: the current click's column is framed in light gray behind its
|
|
1936
|
+
cells (a little larger than them) and its number becomes a filled circle in the text
|
|
1937
|
+
color. Shape and contrast mark it without relying on color; the power colors stay. */
|
|
1938
|
+
[data-hc-ds] .hc-ui-combat-dial[data-current-mark='framed']:not([data-presentation='printed']) .hc-ui-combat-dial__col[data-current] {
|
|
1939
|
+
isolation: isolate;
|
|
1940
|
+
background: none;
|
|
1941
|
+
box-shadow: none;
|
|
1942
|
+
}
|
|
1943
|
+
[data-hc-ds] .hc-ui-combat-dial[data-current-mark='framed']:not([data-presentation='printed']) .hc-ui-combat-dial__col[data-current]::after {
|
|
1944
|
+
content: '';
|
|
1945
|
+
position: absolute;
|
|
1946
|
+
inset: -4px -3px;
|
|
1947
|
+
z-index: -1;
|
|
1948
|
+
border-radius: 8px;
|
|
1949
|
+
background: var(--hc-color-bg-muted-2);
|
|
1950
|
+
box-shadow: inset 0 0 0 1px var(--hc-color-border);
|
|
1951
|
+
}
|
|
1952
|
+
[data-hc-ds] .hc-ui-combat-dial[data-current-mark='framed']:not([data-presentation='printed']) .hc-ui-combat-dial__col[data-current] .hc-ui-combat-dial__cell[data-kind='number'] {
|
|
1953
|
+
border-radius: 50%;
|
|
1954
|
+
background: var(--hc-color-text-primary);
|
|
1955
|
+
color: var(--hc-color-text-inverse);
|
|
1956
|
+
font-weight: 800;
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1918
1959
|
/* `presentation="printed"`: the physical card's dial, at HCUnits' measures (20px
|
|
1919
1960
|
cells, 23px between clicks, 24px between rows); the white legend sits on the
|
|
1920
1961
|
card's dark window. Its numbers use the `font` shorthand, with ROND right after it
|