Files
HMDesign/packages/sw/src/theme/sw-viewer.css
T
shkim4 126a35d60d feat(sw): popup controls, SWSelect / SWSlider, footer and viewer design fixes
Components (new public exports, existing APIs unchanged)
- SWPopupPropertyRow: the property window row (layer / color / line style
  pickers, Figma 26:12250 / 26:12170) for SWPopup content. The SWHeader field
  dropdowns stay header-only; Popup B and 도면 설정 now use the popup pickers.
- SWSelect: native panel select (28px, 1px #948871, radius 4, #F1ECE1, 12px),
  used by Popup 도면 설정 단위 and Viewer 축척 지정 단위 (replaces the HM UI
  Select there and the story-only .sw-viewer-story-select CSS).
- SWSlider: appearance "panel" (default, the gauge the popup used) or
  "property" (the property window gauge), same value / events. Shares the
  property gauge CSS; SWViewerSlider renders SWSlider panel with viewer tokens.

Footer
- --hm-sw-footer-gra-border-orange (Figma gra-border-orange; the aux selected
  border token now references it): Model selected / hover, Layout hover and
  Layout + hover surfaces; 보조기능 / 명령어 전체보기 hover lights both lines
  and an orange ring; category + hover in #FF5C00 (menu-add-hover.svg).
- Model / Layout text stays the Default text (#161410, 12px, 400, no outline)
  on hover and on the orange surface: only the surface changes.
- bg_vacant covers the slot row only: the open pocket of a category tab no
  longer splits where it crosses the last command (e.g. 수정 with one command).

Viewer
- Panel title art keeps 308px (max-width: none against host img resets), so
  panels under 312px (250 x auto, 300px) paint the title from the left edge.

Storybook
- SW/Footer: 기본 Footer (sw-footer--default) and States (sw-footer--states)
  removed; full-footer keeps the live composition only, responsive keeps the
  widths (reference / Figma image sections removed, image files kept); the aux
  Figma comparison moved to the verification Story figma-variants.
- SW/Popup: unit SWSelect, SWSlider A / B section, popup pickers, Popup B state.
2026-10-20 15:20:06 +09:00

489 lines
25 KiB
CSS

/* @hm-design/sw — SW viewer mode (reference: DWG/DXF viewer top menu and floating panels, measured 2026-10-19).
Viewer-only tokens. The three header surfaces reuse the user-confirmed SW tokens of sw.css
(--hm-sw-header-document-* / object-* / property-*). Never touches global selectors or the SWHeader.
Declared on the outermost SW scope only, like sw.css: nested viewer menus / panels inherit the tokens. */
:is(.hm-sw-header, .hm-sw-theme):not(:where(.hm-sw-header, .hm-sw-theme) *) {
/* Header */
--hm-sw-viewer-height: 52px;
--hm-sw-viewer-background: linear-gradient(180deg, #266651 0%, #123328 45%, #0a221d 100%);
--hm-sw-viewer-border-color: #071e18;
--hm-sw-viewer-brand-width: 72px;
/* No logo: no text or icon is drawn; the cap keeps only its slanted edge (no wide empty space). */
--hm-sw-viewer-brand-empty-width: 24px;
--hm-sw-viewer-brand-top: #123328;
--hm-sw-viewer-brand-middle: #205241;
--hm-sw-viewer-brand-bottom: #071e18;
--hm-sw-viewer-text: #fff;
--hm-sw-viewer-muted: #bddfd4;
--hm-sw-viewer-accent: #ffc600;
--hm-sw-viewer-hover: #266651;
--hm-sw-viewer-gap: 4px;
--hm-sw-viewer-radius: 4px;
--hm-sw-viewer-control-height: 40px;
--hm-sw-viewer-button-height: 34px;
--hm-sw-viewer-font-size: 14px;
--hm-sw-viewer-label-size: 11px;
--hm-sw-viewer-icon-size: 16px;
--hm-sw-viewer-disabled-opacity: 0.6;
--hm-sw-viewer-switch-off: #0a221d;
--hm-sw-viewer-switch-bevel: inset 0 1px 0 rgba(255, 255, 255, 0.1), inset 0 -1px 1px rgba(0, 0, 0, 0.25);
/* Icon stroke: the SWHeader icon assets (print / K guide / layer icons) are a fill + a 1px black OUTSIDE stroke
(Figma mask "outside" path). SWViewerIcon draws it as SVG stroke on a copy behind the icon (see SWViewerIcon). */
--hm-sw-viewer-icon-outline-color: var(--hm-sw-header-text-outline-color);
--hm-sw-viewer-icon-outline-width: 1px;
/* Dropdown (light) and More (beige) */
--hm-sw-viewer-menu-background: #fff;
--hm-sw-viewer-menu-border-color: #dedbd2;
--hm-sw-viewer-menu-text: #0a221d;
--hm-sw-viewer-menu-muted: #6e6759;
--hm-sw-viewer-menu-highlight: rgba(189, 223, 212, 0.45);
--hm-sw-viewer-menu-highlight-text: #123328;
--hm-sw-viewer-menu-shadow: 0 0 12px rgba(0, 0, 0, 0.2);
--hm-sw-viewer-menu-item-height: 36px;
--hm-sw-viewer-more-background: #f5f0e5;
--hm-sw-viewer-more-border-color: #897445;
/* Panel: the frame is SWPopup (title bar, title, close, border, radius, shadow). Content tokens map to the
SW property window tokens so viewer content sits on the same surface as every SW popup. */
--hm-sw-viewer-panel-background: var(--hm-sw-property-surface);
--hm-sw-viewer-panel-field-background: var(--hm-sw-property-content);
--hm-sw-viewer-panel-inner-border: var(--hm-sw-property-inner-border);
--hm-sw-viewer-panel-text: var(--hm-sw-property-label);
--hm-sw-viewer-panel-heading: #3e3523;
--hm-sw-viewer-panel-label: #6e6759;
--hm-sw-viewer-panel-primary: #123328;
--hm-sw-viewer-panel-switch-off: var(--hm-sw-property-inner-border);
--hm-sw-viewer-panel-switch-on: #266651;
--hm-sw-viewer-panel-badge-background: var(--hm-sw-property-table);
--hm-sw-viewer-panel-overlay: rgba(0, 0, 0, 0.1);
--hm-sw-viewer-panel-spacing: 12px;
}
.hm-sw-viewer-sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
/* ---------- Header ---------- */
.hm-sw-viewer-header {
container: hm-sw-viewer / inline-size;
position: relative;
box-sizing: border-box;
display: flex;
align-items: flex-start;
gap: 2px;
width: 100%;
min-width: 0;
height: var(--hm-sw-viewer-height);
border: 1px solid var(--hm-sw-viewer-border-color);
background: var(--hm-sw-viewer-background);
color: var(--hm-sw-viewer-text);
font-size: var(--hm-sw-viewer-font-size);
font-weight: 500;
line-height: 20px;
}
.hm-sw-viewer-header__brand {
position: relative;
z-index: 2;
display: flex;
align-items: center;
flex: 0 0 auto;
width: var(--hm-sw-viewer-brand-empty-width);
height: calc(var(--hm-sw-viewer-height) - 2px);
margin-right: -2px;
font-weight: 700;
}
/* With a logo: the reference 72px cap (logo at 24px), wider only for a wider logo. Without: the slanted edge only. */
.hm-sw-viewer-header__brand[data-logo] { width: auto; min-width: var(--hm-sw-viewer-brand-width); padding: 0 25px 0 24px; }
button.hm-sw-viewer-header__brand { text-align: left; }
.hm-sw-viewer-header__brand-shape { position: absolute; inset: 0 auto 0 0; width: calc(100% + 16px); height: 100%; pointer-events: none; }
.hm-sw-viewer-header__brand-mark { position: relative; display: inline-flex; align-items: center; }
.hm-sw-viewer-header__brand-mark > :is(img, svg) { display: block; max-height: 24px; width: auto; }
.hm-sw-viewer-header__document {
display: flex;
align-items: center;
flex: 0 1 clamp(140px, 25cqw, 360px);
width: clamp(220px, 25cqw, 360px);
min-width: 56px;
height: calc(var(--hm-sw-viewer-height) - 2px);
padding: 0 16px 0 24px;
border: 1px solid var(--hm-sw-header-document-border-color);
border-left: 0;
background: var(--hm-sw-header-document-background);
}
.hm-sw-viewer-header__document-name { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.hm-sw-viewer-header__object {
display: flex;
align-items: center;
flex: 1 0 auto;
min-width: 0;
height: calc(var(--hm-sw-viewer-height) - 2px);
gap: var(--hm-sw-viewer-gap);
padding-inline: var(--hm-sw-viewer-gap);
border: 1px solid var(--hm-sw-header-object-border-color);
border-radius: var(--hm-sw-header-object-radius);
background: var(--hm-sw-header-object-background);
}
.hm-sw-viewer-header__group {
display: flex;
align-items: center;
gap: var(--hm-sw-viewer-gap);
min-height: var(--hm-sw-viewer-control-height);
padding-inline: var(--hm-sw-viewer-gap);
}
.hm-sw-viewer-header__group[data-surface="field"] {
border: 1px solid var(--hm-sw-header-property-border-color);
border-radius: var(--hm-sw-header-property-radius);
background: var(--hm-sw-header-property-background);
box-shadow: var(--hm-sw-header-property-shadow);
}
.hm-sw-viewer-header__actions {
display: flex;
align-items: center;
align-self: stretch;
gap: var(--hm-sw-viewer-gap);
margin-left: auto;
padding-left: 6px;
}
/* Buttons, menu buttons and toggles: transparent, #266651 hover, #FFC600 pressed / open / on (no selected box). */
.hm-sw-viewer-header .hm-sw-viewer-header__button {
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
gap: 8px;
height: var(--hm-sw-viewer-button-height);
padding: 6px 14px;
border: 1px solid transparent;
border-radius: var(--hm-sw-viewer-radius);
color: var(--hm-sw-viewer-text);
font-weight: 500;
line-height: 20px;
white-space: nowrap;
}
.hm-sw-viewer-header .hm-sw-viewer-header__button[data-kind="toggle"] { height: var(--hm-sw-viewer-control-height); padding: 0 8px; }
.hm-sw-viewer-header .hm-sw-viewer-header__button[data-icon-only] { min-width: var(--hm-sw-viewer-button-height); padding: 0 8px; }
/* Always-icon buttons (info, More): the reference 32 x 40 icon button. */
.hm-sw-viewer-header .hm-sw-viewer-header__button[data-icon-only="always"] { min-width: 32px; width: 32px; height: var(--hm-sw-viewer-control-height); padding: 0 8px; }
.hm-sw-viewer-header .hm-sw-viewer-header__button:hover:not(:disabled) { background: var(--hm-sw-viewer-hover); }
.hm-sw-viewer-header .hm-sw-viewer-header__button:active:not(:disabled),
.hm-sw-viewer-header .hm-sw-viewer-header__button:is([data-state="open"], [data-state="on"]) { color: var(--hm-sw-viewer-accent); }
.hm-sw-viewer-header .hm-sw-viewer-header__button:is([data-state="open"], [data-state="on"]):not(:hover) { background: transparent; }
.hm-sw-viewer-header :is(.hm-sw-viewer-header__button, .hm-sw-viewer-header__tab):disabled { opacity: var(--hm-sw-viewer-disabled-opacity); cursor: not-allowed; }
.hm-sw-viewer-header__icon, .hm-sw-viewer-header__chevron { display: inline-flex; width: var(--hm-sw-viewer-icon-size); height: var(--hm-sw-viewer-icon-size); }
.hm-sw-viewer-header__icon > svg, .hm-sw-viewer-header__chevron > svg { width: 100%; height: 100%; }
/* SWViewerIcon: the outline copy (black SVG stroke) right behind the untouched icon. */
.hm-sw-viewer-icon { position: relative; display: inline-flex; width: 100%; height: 100%; }
.hm-sw-viewer-icon__outline, .hm-sw-viewer-icon__glyph { display: inline-flex; width: 100%; height: 100%; }
.hm-sw-viewer-icon__outline { position: absolute; inset: 0; overflow: visible; }
.hm-sw-viewer-icon__glyph { position: relative; }
.hm-sw-viewer-icon svg { width: 100%; height: 100%; overflow: visible; }
/* Tabs (Model / Layout): 40px triggers with an 11px count; the active one turns #FFC600. */
.hm-sw-viewer-header__tabs { display: flex; align-items: center; gap: var(--hm-sw-viewer-gap); }
.hm-sw-viewer-header .hm-sw-viewer-header__tab {
display: inline-flex;
align-items: center;
gap: var(--hm-sw-viewer-gap);
height: var(--hm-sw-viewer-control-height);
padding: 0 8px;
border: 1px solid transparent;
border-radius: var(--hm-sw-viewer-radius);
color: var(--hm-sw-viewer-text);
font-weight: 500;
line-height: 1.4;
white-space: nowrap;
}
.hm-sw-viewer-header .hm-sw-viewer-header__tab:hover:not(:disabled) { background: var(--hm-sw-viewer-hover); }
.hm-sw-viewer-header .hm-sw-viewer-header__tab[data-state="active"] { color: var(--hm-sw-viewer-accent); }
.hm-sw-viewer-header__count { font-size: var(--hm-sw-viewer-label-size); font-weight: 400; font-variant-numeric: tabular-nums; }
/* Switch fields (2.5D, 어두운 배경): 11px muted caption above the switch. */
.hm-sw-viewer-header__switch-field {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--hm-sw-viewer-gap);
min-height: var(--hm-sw-viewer-control-height);
padding-inline: 8px;
}
.hm-sw-viewer-header__switch-label { color: var(--hm-sw-viewer-muted); font-size: var(--hm-sw-viewer-label-size); font-weight: 400; line-height: 1; white-space: nowrap; }
.hm-sw-viewer-header :is(.hm-sw-viewer-header__button, .hm-sw-viewer-header__tab, .hm-sw-viewer-header__brand, .hm-sw-viewer-switch):focus-visible {
outline: 2px solid var(--hm-sw-viewer-accent);
outline-offset: 2px;
}
/* Text and icon stroke (2026-10-19 request): the SWHeader black outline on the viewer header, same tokens and
method — an outside outline of the glyph / icon shape, never a box border.
Text: 14px = --hm-sw-header-text-outline (1.3px black), 11px captions / counts / status = --hm-sw-header-label-outline
(1px black), as SWHeader's 12px labels. Icons: SWViewerIcon (SVG stroke, see the token). Fill color, size,
weight and spacing are unchanged; hover / active / open change only the fill, disabled fades the whole button
(opacity) like SWHeader. Dropdown faces (light / beige) and panels get no outline, like SWHeader's More menu. */
.hm-sw-viewer-header :is(
.hm-sw-viewer-header__brand-mark, .hm-sw-viewer-header__document-name, .hm-sw-viewer-header__label, .hm-sw-viewer-header__tab
) {
text-shadow: var(--hm-sw-header-text-outline);
}
.hm-sw-viewer-header :is(.hm-sw-viewer-header__count, .hm-sw-viewer-header__switch-label, .hm-sw-viewer-status__label) {
text-shadow: var(--hm-sw-header-label-outline);
}
/* Clipped (ellipsis) file name: the outline may paint 2px outside the box instead of being cut. */
.hm-sw-viewer-header .hm-sw-viewer-header__document-name {
overflow: clip;
overflow-clip-margin: var(--hm-sw-header-text-outline-room);
}
/* Status */
.hm-sw-viewer-status {
display: flex;
align-items: center;
gap: var(--hm-sw-viewer-gap);
padding-inline: 8px;
color: var(--hm-sw-viewer-muted);
font-size: var(--hm-sw-viewer-label-size);
font-weight: 400;
white-space: nowrap;
}
.hm-sw-viewer-status__icon { display: inline-flex; width: var(--hm-sw-viewer-icon-size); height: var(--hm-sw-viewer-icon-size); }
.hm-sw-viewer-status[data-state="error"] { color: var(--hm-sw-viewer-accent); }
.hm-sw-viewer-status__spin { animation: hm-sw-viewer-spin 1s linear infinite; }
@keyframes hm-sw-viewer-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .hm-sw-viewer-status__spin { animation: none; } }
/* Narrow header (reference breakpoints, measured on the header itself). */
@container hm-sw-viewer (max-width: 1179.98px) {
.hm-sw-viewer-header__object { gap: 2px; padding-inline: 2px; }
.hm-sw-viewer-header__group { gap: 2px; padding-inline: 2px; }
.hm-sw-viewer-header__actions { padding-left: 2px; gap: 2px; }
.hm-sw-viewer-status { padding-inline: 2px; }
}
@container hm-sw-viewer (max-width: 559.98px) {
.hm-sw-viewer-header__document { padding-right: 8px; }
.hm-sw-viewer-status__label { display: none; }
}
/* ---------- Switch (header / panel faces) ---------- */
.hm-sw-theme .hm-sw-viewer-switch {
position: relative;
display: inline-flex;
align-items: center;
flex-shrink: 0;
width: 36px;
height: 20px;
padding: 2px;
border-radius: 9999px;
background: var(--hm-sw-viewer-switch-off);
box-shadow: var(--hm-sw-viewer-switch-bevel);
transition: background-color 0.15s;
}
.hm-sw-viewer-switch__thumb { display: block; width: 16px; height: 16px; border-radius: 9999px; background: var(--hm-sw-viewer-text); transition: transform 0.15s; }
.hm-sw-viewer-switch[data-state="checked"] { background: var(--hm-sw-viewer-accent); }
.hm-sw-viewer-switch[data-state="checked"] .hm-sw-viewer-switch__thumb { transform: translateX(16px); background: var(--hm-sw-viewer-switch-off); }
.hm-sw-theme .hm-sw-viewer-switch:disabled { opacity: var(--hm-sw-viewer-disabled-opacity); cursor: not-allowed; }
.hm-sw-viewer-panel .hm-sw-viewer-switch { background: var(--hm-sw-viewer-panel-switch-off); box-shadow: none; }
.hm-sw-viewer-panel .hm-sw-viewer-switch .hm-sw-viewer-switch__thumb { background: #fff; }
.hm-sw-viewer-panel .hm-sw-viewer-switch[data-state="checked"] { background: var(--hm-sw-viewer-panel-switch-on); }
@media (prefers-reduced-motion: reduce) { .hm-sw-viewer-switch, .hm-sw-viewer-switch__thumb { transition: none; } }
/* ---------- Dropdown ---------- */
/* The menu renders next to its trigger inside the header flex rows: the wrapper must not become a flex item, or the
row gains one gap while a menu is open (file name well shrinks, trigger shifts). The fixed list is out of flow. */
.hm-sw-viewer-menu-root { display: contents; }
.hm-sw-viewer-menu {
position: fixed;
z-index: 60;
display: flex;
flex-direction: column;
min-width: 160px;
max-width: calc(100vw - 8px);
max-height: min(640px, calc(100dvh - 8px));
overflow-y: auto;
padding: 4px;
border: 1px solid var(--hm-sw-viewer-menu-border-color);
border-radius: var(--hm-sw-viewer-radius);
background: var(--hm-sw-viewer-menu-background);
box-shadow: var(--hm-sw-viewer-menu-shadow);
color: var(--hm-sw-viewer-menu-text);
font-size: 14px;
font-weight: 400;
line-height: 20px;
outline: none;
}
.hm-sw-viewer-menu[data-surface="beige"] { background: var(--hm-sw-viewer-more-background); border-color: var(--hm-sw-viewer-more-border-color); }
.hm-sw-viewer-menu .hm-sw-viewer-menu__item {
display: flex;
align-items: center;
gap: 8px;
width: 100%;
min-height: var(--hm-sw-viewer-menu-item-height);
padding: 0 12px;
border-radius: 2px;
color: inherit;
text-align: left;
white-space: nowrap;
outline: none;
}
.hm-sw-viewer-menu .hm-sw-viewer-menu__item:is(:focus, :hover, [data-state="open"]):not([aria-disabled]) { background: var(--hm-sw-viewer-menu-highlight); color: var(--hm-sw-viewer-menu-highlight-text); }
.hm-sw-viewer-menu .hm-sw-viewer-menu__item[aria-disabled] { opacity: 0.5; cursor: not-allowed; }
.hm-sw-viewer-menu .hm-sw-viewer-menu__item:focus-visible { outline: none; }
.hm-sw-viewer-menu__icon { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 16px; width: 16px; height: 16px; }
.hm-sw-viewer-menu__icon:empty { display: none; }
.hm-sw-viewer-menu__item[role="menuitemcheckbox"] .hm-sw-viewer-menu__icon,
.hm-sw-viewer-menu__item[role="menuitemradio"] .hm-sw-viewer-menu__icon { display: inline-flex; }
.hm-sw-viewer-menu__icon > svg { width: 16px; height: 16px; }
.hm-sw-viewer-menu__dot { width: 8px; height: 8px; border-radius: 9999px; background: currentColor; }
.hm-sw-viewer-menu__text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.hm-sw-viewer-menu__shortcut { margin-left: auto; color: var(--hm-sw-viewer-menu-muted); font-size: 12px; letter-spacing: 0.05em; }
.hm-sw-viewer-menu__chevron { display: inline-flex; margin-left: auto; color: var(--hm-sw-viewer-menu-muted); }
.hm-sw-viewer-menu__label { padding: 6px 12px; color: var(--hm-sw-viewer-menu-muted); font-size: 12px; font-weight: 500; line-height: 18px; }
.hm-sw-viewer-menu__separator { flex: 0 0 1px; height: 1px; margin: 4px -4px; background: var(--hm-sw-viewer-menu-border-color); }
.hm-sw-viewer-menu[data-surface="beige"] .hm-sw-viewer-menu__separator { background: var(--hm-sw-viewer-panel-inner-border); }
/* ---------- Panel (SWPopup frame + viewer window behavior) ---------- */
.hm-sw-viewer-panel-backdrop { inset: 0; background: var(--hm-sw-viewer-panel-overlay); }
.hm-sw-viewer-panel[data-collapsed] .hm-sw-property__body { display: none; }
.hm-sw-viewer-panel[data-draggable] .hm-sw-property__titlebar { cursor: grab; touch-action: none; user-select: none; }
.hm-sw-viewer-panel[data-dragging] .hm-sw-property__titlebar { cursor: grabbing; }
/* Any width: the Figma title art keeps its 308px curve at the close button (right-aligned; at 314px this is exactly
the SWPopup position), and a stretched copy of the same art fills the flat part on the left of wider panels.
The right one hides its own left 20px (left edge + corner) and the left copy ends exactly there: no seam, no
doubled shadow. */
/* max-width: none: a host img reset (e.g. Tailwind preflight max-width: 100%) shrank the art in panels under 312px,
so its clipped left 20px left the start of the title bar unpainted (2026-10-20, 250px minimum width). */
.hm-sw-viewer-panel .hm-sw-property__title-art { left: auto; right: 4px; max-width: none; clip-path: inset(-4px -4px -4px 20px); }
.hm-sw-viewer-panel .hm-sw-property__titlebar::before {
content: "";
position: absolute;
z-index: 1;
left: 0;
top: -2px;
width: max(0px, calc(100% - 292px));
height: 38px;
background: url("../assets/property-title-single.svg") left top / calc(100% + 288px) 38px no-repeat;
transform: scaleY(-1);
pointer-events: none;
}
.hm-sw-viewer-panel__actions { position: relative; z-index: 2; display: flex; flex-shrink: 0; align-items: center; height: 30px; }
/* Title-bar buttons: SW text-only look (no face), #FFC600 on hover like the SW title-bar controls. */
.hm-sw-viewer-panel :is(.hm-sw-viewer-panel__icon-button, .hm-sw-viewer-button[data-variant="ghost"]) {
display: inline-flex;
align-items: center;
justify-content: center;
width: 26px;
height: 26px;
padding: 0;
border: 0;
border-radius: 0;
background: transparent;
color: var(--hm-sw-viewer-muted);
}
.hm-sw-viewer-panel :is(.hm-sw-viewer-panel__icon-button, .hm-sw-viewer-button[data-variant="ghost"]):hover:not(:disabled) { background: transparent; color: var(--hm-sw-header-selected-color); }
.hm-sw-viewer-panel :is(.hm-sw-viewer-panel__icon-button, .hm-sw-viewer-button[data-variant="ghost"]):focus-visible { outline: 2px solid var(--hm-sw-header-selected-color); outline-offset: -2px; }
.hm-sw-viewer-panel :is(.hm-sw-viewer-panel__icon-button, .hm-sw-viewer-button[data-variant="ghost"]) svg { width: 16px; height: 16px; }
.hm-sw-viewer-panel__footer {
display: flex;
flex-shrink: 0;
justify-content: flex-end;
gap: 8px;
padding: 7px;
border-top: 1px solid var(--hm-sw-viewer-panel-inner-border);
}
/* Panel content */
.hm-sw-viewer-section { display: flex; flex-direction: column; gap: 12px; }
.hm-sw-viewer-section[data-surface="card"] {
padding: var(--hm-sw-viewer-panel-spacing);
border: 1px solid var(--hm-sw-viewer-panel-inner-border);
border-radius: var(--hm-sw-viewer-radius);
background: var(--hm-sw-viewer-panel-field-background);
box-shadow: inset 0 1px 0 #fff;
}
.hm-sw-viewer-section__title { margin: 0; color: var(--hm-sw-viewer-panel-heading); font-size: 12px; font-weight: 700; line-height: 16px; letter-spacing: 0.025em; text-transform: uppercase; }
.hm-sw-viewer-hint { margin: 0; color: var(--hm-sw-viewer-panel-heading); font-size: 12px; line-height: 16px; }
.hm-sw-viewer-field { display: flex; flex-direction: column; gap: 6px; }
.hm-sw-viewer-field[data-disabled] { opacity: 0.5; pointer-events: none; }
.hm-sw-viewer-field__row { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 20px; }
.hm-sw-viewer-field__label { min-width: 0; color: var(--hm-sw-viewer-panel-label); font-size: 14px; font-weight: 500; line-height: 20px; }
.hm-sw-viewer-field__control { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
.hm-sw-viewer-field__unit { color: var(--hm-sw-viewer-panel-label); font-size: 12px; }
.hm-sw-theme .hm-sw-viewer-input {
box-sizing: border-box;
width: 80px;
height: 28px;
padding: 0 10px;
border: 1px solid var(--hm-sw-viewer-panel-inner-border);
border-radius: var(--hm-sw-viewer-radius);
background: var(--hm-sw-viewer-panel-field-background);
color: var(--hm-sw-viewer-panel-text);
font: inherit;
font-size: 12px;
line-height: 18px;
}
.hm-sw-theme .hm-sw-viewer-input:focus-visible { outline: 2px solid var(--hm-sw-viewer-panel-switch-on); outline-offset: -1px; }
.hm-sw-theme .hm-sw-viewer-input:disabled { opacity: 0.5; }
/* SWViewerSlider = SWSlider appearance="panel" (sw.css, 2026-10-20): the shared gauge rules painted with the
viewer panel tokens, so the viewer look and its theme overrides are unchanged. */
.hm-sw-viewer-slider {
--hm-sw-slider-panel-range: var(--hm-sw-viewer-panel-switch-on);
--hm-sw-slider-panel-track: var(--hm-sw-viewer-panel-background);
--hm-sw-slider-panel-thumb: #fff;
}
/* SWSelect inside viewer panels reads the viewer panel tokens (same values; viewer theme overrides follow). */
.hm-sw-viewer-panel { --hm-sw-select-border-color: var(--hm-sw-viewer-panel-inner-border); --hm-sw-select-background: var(--hm-sw-viewer-panel-field-background); --hm-sw-select-text: var(--hm-sw-viewer-panel-text); }
/* Viewer rows dim a disabled field as a whole (SWViewerField 50%); the slider keeps its own opacity as before. */
.hm-sw-theme .hm-sw-viewer-slider:disabled { opacity: 1; }
.hm-sw-theme .hm-sw-viewer-button {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 4px;
height: 24px;
padding: 0 8px;
border: 1px solid var(--hm-sw-viewer-panel-primary);
border-radius: var(--hm-sw-viewer-radius);
background: #fff;
color: var(--hm-sw-viewer-panel-primary);
font-size: 12px;
font-weight: 500;
line-height: 16px;
white-space: nowrap;
}
.hm-sw-theme .hm-sw-viewer-button[data-variant="outline"]:hover:not(:disabled) { background: var(--hm-sw-viewer-panel-field-background); }
.hm-sw-theme .hm-sw-viewer-button[data-variant="primary"] { background: var(--hm-sw-viewer-panel-primary); color: #fff; }
/* tone="green" (e.g. 전체 켜기 / 전체 끄기): default unchanged. Hover = the primary (확인) button hover, the same token;
pressed = the primary button face. White text as on the primary button. Back to default / hover after the press. */
.hm-sw-theme .hm-sw-viewer-button[data-tone="green"]:hover:not(:disabled) { border-color: var(--hm-sw-viewer-hover); background: var(--hm-sw-viewer-hover); color: #fff; }
.hm-sw-theme .hm-sw-viewer-button[data-tone="green"]:active:not(:disabled) { border-color: var(--hm-sw-viewer-panel-primary); background: var(--hm-sw-viewer-panel-primary); color: #fff; }
.hm-sw-theme .hm-sw-viewer-button[data-variant="primary"]:hover:not(:disabled) { background: var(--hm-sw-viewer-hover); border-color: var(--hm-sw-viewer-hover); }
.hm-sw-theme .hm-sw-viewer-button:focus-visible { outline: 2px solid var(--hm-sw-viewer-panel-switch-on); outline-offset: 1px; }
.hm-sw-theme .hm-sw-viewer-button:disabled { opacity: 0.5; cursor: not-allowed; }
.hm-sw-viewer-button__icon { display: inline-flex; width: 16px; height: 16px; }
.hm-sw-viewer-button__icon > svg { width: 100%; height: 100%; }
.hm-sw-viewer-badge { display: inline-flex; align-items: center; padding: 2px 8px; border-radius: var(--hm-sw-viewer-radius); background: var(--hm-sw-viewer-panel-badge-background); color: var(--hm-sw-viewer-panel-label); font-size: 12px; font-weight: 500; line-height: 18px; font-variant-numeric: tabular-nums; }
/* Corner resize grip (replaces native resize: same corner and glyph idea, works in every browser and with
pointer capture; the size stays within min / 90% of the bounds / the bounds edge). */
.hm-sw-viewer-panel__resize {
position: absolute;
right: 0;
bottom: 0;
z-index: 1;
width: 14px;
height: 14px;
cursor: nwse-resize;
touch-action: none;
background:
linear-gradient(135deg, transparent 0 55%, var(--hm-sw-viewer-panel-inner-border) 55% 62%, transparent 62% 72%, var(--hm-sw-viewer-panel-inner-border) 72% 79%, transparent 79%);
}