Files
HMDesign/packages/sw/src/theme/sw-viewer.css
T
shkim4 81127a4e44
Deploy Storybook / deploy (push) Successful in 1m14s
fix(sw): remove top margin from card sections
2026-10-23 12:54:06 +09:00

796 lines
47 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* @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;
/* 2026-10-21 user request: the solid color of the Storybook viewer canvas (--sw-story-canvas base #0a0a0b), no gradient. */
--hm-sw-viewer-background: #0a0a0b;
--hm-sw-viewer-border-color: #071e18;
/* 2026-10-23: auto = the SWHeader home box (12px incl. the header border + logo + 36px): 79px with the 32 x 17
example logo, wider or narrower with the logo. */
--hm-sw-viewer-brand-width: auto;
/* These four are unused since 2026-10-23 (the cap is the SWHeader home shape; no cap without a logo); kept so
existing themes that set them stay valid. */
--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;
/* Header switches (2.5D, 어두운 배경), 2026-10-22 (user-picked): OFF recedes (darkest track, dim gray-green knob);
ON reads first without white (header hover green track, muted mint knob). No yellow and no ring, so both states
keep the same 36 x 20 look. Panel switches keep their own. */
--hm-sw-viewer-switch-off: #020a07;
--hm-sw-viewer-switch-thumb-off: #5f7a71;
--hm-sw-viewer-switch-on: var(--hm-sw-viewer-hover);
--hm-sw-viewer-switch-thumb-on: var(--hm-sw-viewer-muted);
--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 (2026-10-23): the SWHeader home — the same shape (shared .hm-sw-header__home-bg 9-slice of the Figma
asset: gradient, stroke, shadow, slant), the same box (12px + logo + 36px, 11px here + the 1px header border; the
logo centered) and the same 17px overlap of the next part, so the logo and the file-name area sit where SWHeader
puts them. No hover layer: the viewer cap keeps its own (focus only) look. Without a logo there is no cap. */
.hm-sw-viewer-header__brand[data-logo] {
justify-content: center;
box-sizing: border-box;
width: var(--hm-sw-viewer-brand-width);
padding: 0 36px 0 11px;
margin-right: -17px;
overflow: hidden;
/* The 17px overlap must not take the clicks of the next part (Open icon / file name): only the surface behind the
shape (::before, up to where the next part starts) is the cap's hit area. Focus and keyboard are unchanged. */
pointer-events: none;
}
.hm-sw-viewer-header__brand[data-logo]::before { pointer-events: auto; }
button.hm-sw-viewer-header__brand { text-align: left; }
.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;
/* SWHeader file-name surface: the Figma gradient stroke through the transparent top / right / bottom 1px. */
border: 1px solid transparent;
border-left: 0;
background: var(--hm-sw-header-document-background) padding-box, var(--hm-sw-header-document-border-gradient) border-box;
}
.hm-sw-viewer-header__document-name { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
/* Logo menu (2026-10-21): the brand cap is the trigger of the SWHeader `...` menu (SWHeaderMore, sw.css). The wrapper
takes the cap's place in the row but is not positioned: the cap keeps its own layer (z-index 2 over the file name,
like the SWHeader logo), and the menu is placed by the header container itself — flush under the header's bottom
border (100% of its padding box + its 1px border) at the left edge of the cap, at any header height or width. */
.hm-sw-viewer-header__logo-menu.hm-sw-header__more {
position: static;
display: flex;
flex: 0 0 auto;
height: calc(var(--hm-sw-viewer-height) - 2px);
margin-left: 0;
}
.hm-sw-viewer-header__logo-menu > .hm-sw-header__more-menu {
top: calc(100% + 1px);
left: 0;
font-size: var(--hm-sw-header-font-size);
font-weight: 400;
line-height: normal;
}
/* Logo menu (2026-10-21): the size, spacing and type of the viewer header dropdowns (SWViewerMenu); its colors are
those of the SWHeader `...` menu it is (sw.css .hm-sw-header__more-menu: face, border, shadow, hover); its place
stays flush under the header. Only this menu: the document list stays the SWHeader file-name list. */
.hm-sw-viewer-header__logo-menu > .hm-sw-header__more-menu {
min-width: 160px;
padding: 4px;
border-width: 1px;
border-radius: var(--hm-sw-viewer-radius);
color: var(--hm-sw-header-text-color);
font-size: 14px;
font-weight: 400;
line-height: 20px;
}
.hm-sw-viewer-header__logo-menu .hm-sw-header__more-item {
gap: 8px;
min-height: var(--hm-sw-viewer-menu-item-height);
padding: 0 12px;
color: inherit;
}
.hm-sw-viewer-header__logo-menu .hm-sw-header__more-item:is(:hover, :focus):not(:disabled) { background: var(--hm-sw-header-hover); outline: none; }
.hm-sw-viewer-header__logo-menu .hm-sw-header__more-item:disabled { opacity: 0.5; }
/* Title = SWViewerMenu label, directly above its items (one group, no divider); icons = SWViewerMenu icon slot. */
.hm-sw-viewer-header__logo-menu .hm-sw-header__more-title { min-height: 0; padding: 6px 12px; font-size: 12px; font-weight: 500; line-height: 18px; }
/* Document list (2026-10-21): the SWHeader file-name button and dropdown (SWHeaderDocumentTitle) fill the well.
The button draws the well (border, gradient), sized to the viewer row; the text keeps the viewer inset. */
.hm-sw-viewer-header__document[data-list] {
--hm-sw-header-bar-height: calc(var(--hm-sw-viewer-height) - 2px);
padding: 0;
border: 0;
background: none;
font-size: var(--hm-sw-header-font-size);
line-height: normal;
}
/* Header Open (2026-10-21, `onDocumentOpen`): SWHeader's documentOpenPlacement="header" surface (SWToolButton
appearance="document", the file-name surface at its content width) right after the logo, sized to the viewer row,
with the label after a folder icon (no border, no face). Icon only when the header has no room (measured,
SWViewerHeader); the file name after it has no left padding (2026-10-21 user request). */
.hm-sw-viewer-header > .hm-sw-header__document[data-tool] {
--hm-sw-header-bar-height: calc(var(--hm-sw-viewer-height) - 2px);
font-size: var(--hm-sw-header-font-size);
line-height: normal;
}
.hm-sw-viewer-header .hm-sw-viewer-header__open { padding: 0 12px 0 24px; }
.hm-sw-viewer-header__open .hm-sw-header__document-name { display: inline-flex; align-items: center; gap: 8px; overflow: visible; }
.hm-sw-viewer-header__open-icon {
display: inline-flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
/* 2026-10-21 user request: the icon area is the 16 x 16 icon itself, no margin. */
width: var(--hm-sw-viewer-icon-size);
height: var(--hm-sw-viewer-icon-size);
margin: 0;
/* 2026-10-21 user request: no border and no face (transparent); the icon keeps its color, size and place. */
border: 0;
background: transparent;
box-shadow: none;
text-shadow: none;
}
/* The folder icon carries the black icon outline of every viewer header icon (SWViewerIcon, 2026-10-21 user request). */
.hm-sw-viewer-header__open-icon > :is(svg, .hm-sw-viewer-icon) { width: var(--hm-sw-viewer-icon-size); height: var(--hm-sw-viewer-icon-size); }
.hm-sw-viewer-header > .hm-sw-header__document[data-tool] + .hm-sw-viewer-header__document { padding-left: 0; }
.hm-sw-viewer-header__document[data-list] > .hm-sw-header__document { flex: 1 1 auto; min-width: 0; }
/* No file open button before it: the file name starts 10px after the slanted logo edge (at mid height), as in
SWHeader (text 10px after its home slant; measured 10.5px here with 18px). */
.hm-sw-viewer-header__document[data-list] .hm-sw-header__document-button { padding: 0 16px 0 18px; }
/* Right after the logo cap (2026-10-23, the SWHeader home shape and 17px overlap): the first part starts 8px in (user
value; was 24px / 18px for the former viewer slant, which doubled the space after the logo, then 5px). */
:is(.hm-sw-viewer-header__brand, .hm-sw-viewer-header__logo-menu) + .hm-sw-header__document[data-tool] > .hm-sw-viewer-header__open,
:is(.hm-sw-viewer-header__brand, .hm-sw-viewer-header__logo-menu) + .hm-sw-viewer-header__document[data-list] .hm-sw-header__document-button { padding-left: 8px; }
/* No logo (2026-10-23): no cap, so the first part (Open or the file name) starts the row 12px in, like SWHeader. */
.hm-sw-viewer-header > .hm-sw-header__document[data-tool]:first-child > .hm-sw-viewer-header__open,
.hm-sw-viewer-header > .hm-sw-viewer-header__document[data-list]:first-child .hm-sw-header__document-button { padding-left: 12px; }/* After the file open button (2026-10-21 user decision): 8px in. */
.hm-sw-viewer-header > .hm-sw-header__document[data-tool] + .hm-sw-viewer-header__document[data-list] .hm-sw-header__document-button { padding: 0 16px 0 8px; }
/* The list (SWHeader face, placement and rows unchanged) is never narrower than the file-name button it opens from:
its outer width is at least the button's (100% of the wrapper, plus the two borders the list starts left of it) and
at least the SWHeader list width; longer rows widen it. min-width wins over the SWHeader max-width. */
.hm-sw-viewer-header__document[data-list] .hm-sw-header__document-menu {
width: max-content;
min-width: max(
calc(var(--hm-sw-header-document-menu-width) + 2 * var(--hm-sw-header-document-menu-border-width)),
calc(100% + 2 * var(--hm-sw-header-document-menu-border-width))
);
}
/* 2026-10-21 user request: viewer file rows show the name only (no icon, no icon gap); rows, hover and the current
file color are unchanged. The SWHeader document list keeps its icons. */
.hm-sw-viewer-header__document[data-list] .hm-sw-header__document-icon { display: none; }
/* Trailing strip (2026-10-21 user request): status, the trailing icon buttons (e.g. 정보 / license) and SWHeader minimize /
close (SWHeaderWindowControls) are separate full-height segments in one continuous strip at the right end, as the
SWHeader window area (print · K | window move | minimize · close): its face and 1px border color, a 1px line before
a segment (none around the license button), no gap, top and bottom on the object surface border. The strip ends at the object surface edge, as in SWHeader. Status stays display only. */
.hm-sw-viewer-header__object:has(> .hm-sw-viewer-header__actions > :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons):last-child) { padding-right: 0; }
/* Viewer header dropdown colors (2026-10-21): the menus of the header — menu buttons, More and their submenus — use the
colors of the SWHeader `...` menu (sw.css .hm-sw-header__more-menu): its face and shadow (fixed values there), the
object border token, the header text, secondary text at 80% (as its values) and the white 8% row hover with the text
unchanged. Size, spacing and type stay SWViewerMenu. A standalone SWViewerMenu (context menu) and the document list
keep their own colors. */
.hm-sw-viewer-header .hm-sw-viewer-menu[data-surface] {
border-color: var(--hm-sw-header-object-border-color);
background: #0e3d2f;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
color: var(--hm-sw-header-text-color);
}
.hm-sw-viewer-header .hm-sw-viewer-menu .hm-sw-viewer-menu__item:is(:focus, :hover, [data-state="open"]):not([aria-disabled]) {
background: var(--hm-sw-header-hover);
color: inherit;
}
.hm-sw-viewer-header .hm-sw-viewer-menu :is(.hm-sw-viewer-menu__label, .hm-sw-viewer-menu__shortcut, .hm-sw-viewer-menu__chevron) { color: inherit; opacity: 0.8; }
.hm-sw-viewer-header .hm-sw-viewer-menu .hm-sw-viewer-menu__separator { background: var(--hm-sw-header-document-menu-divider-color); }
/* Measured responsive steps (2026-10-21, SWViewerHeader measureRoom): set only inside one layout pass, never painted.
Every part at its natural width: the file name at its usual flex basis (2026-10-21 user request: the header width
decides it, never the length of the name, so a short and a long name give the same steps, Open label and widths),
the object surface neither stretched nor shrunk, the trailing area without its auto margin. */
.hm-sw-viewer-header[data-measuring] .hm-sw-viewer-header__document { flex: 0 0 clamp(140px, 25cqw, 360px); }
.hm-sw-viewer-header[data-measuring] .hm-sw-viewer-header__object { flex: 0 0 auto; }
.hm-sw-viewer-header[data-measuring] .hm-sw-viewer-header__actions { margin-left: 0; }
/* While the logo menu or the document list is open, the header takes the viewer dropdown layer (SWViewerMenu, 60) so
the parts hanging below it stay above SWViewerPanel popups (41+). Inside, the SWHeader order is kept: the logo cap
(z-index 2) over the file name and its list (z-index 1), so an open list never covers the logo. Closed: no layer. */
.hm-sw-viewer-header:has(> .hm-sw-viewer-header__logo-menu > .hm-sw-header__more-menu, > .hm-sw-viewer-header__document .hm-sw-header__document-menu) { z-index: 60; }
.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);
/* SWHeader object surface: the Figma gradient stroke through the transparent 1px border. */
border: 1px solid transparent;
border-radius: var(--hm-sw-header-object-radius);
background: var(--hm-sw-header-object-background) padding-box, var(--hm-sw-header-object-border-gradient) border-box;
}
.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; Hover, pressed / open / on = text and icon #FFC600 (no face, no
selected box; 2026-10-21 user request: the former #266651 hover face is removed, size and position never change). */
.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) { color: var(--hm-sw-viewer-accent); }
.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) { color: var(--hm-sw-viewer-accent); }
.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);
}
/* Bold (2026-10-20 user request): file name, button labels (파일열기 · 샘플 · 전체보기 · 레이어 · 설정 · 속성) and the
Model / Layout tabs. Counts, captions and status keep their own weight; size, color and outline are unchanged. */
.hm-sw-viewer-header :is(.hm-sw-viewer-header__document-name, .hm-sw-viewer-header__label, .hm-sw-viewer-header__tab) {
font-weight: 700;
}
/* 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; } }
/* Trailing strip segments (see the strip note above the dropdown colors). After the button rules so the strip
height wins over the 40px icon button. */
.hm-sw-viewer-header .hm-sw-viewer-header__actions > :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons) {
align-self: stretch;
height: auto;
border-radius: 0;
background: var(--hm-sw-header-document-background);
/* Only the 1px line before a segment: top, bottom and right are the object surface border itself, so every segment
(and the license button between them) has the same top and bottom edge (2026-10-21; no doubled lines). */
box-shadow: inset 1px 0 0 var(--hm-sw-header-document-border-color);
position: relative;
}
/* Strip outline (2026-10-23): the file-name gradient stroke (--hm-sw-header-document-border-gradient) over the object
border band above and below every segment, and right of the last one. Each segment's ::after is its own box with a
1px transparent border whose border image is pushed out by exactly that border width (border-image-outset: 1), so it
lands on the object's 1px band at any zoom (both are rounded to device pixels the same way). The segments keep their
size and place; nothing is painted inside them, so content, hover, focus and clicks are unchanged. */
.hm-sw-viewer-header .hm-sw-viewer-header__actions > :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons)::after {
content: "";
position: absolute;
inset: 0;
border: 0 solid transparent;
border-block-width: 1px;
border-image: var(--hm-sw-header-document-border-gradient) 1 / 1 / 1 0;
pointer-events: none;
}
.hm-sw-viewer-header .hm-sw-viewer-header__actions > :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons):last-child::after {
border-right-width: 1px;
border-image-outset: 1 1 1 0;
}
.hm-sw-viewer-header__actions > :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons) + :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons) { margin-left: calc(-1 * var(--hm-sw-viewer-gap)); }
.hm-sw-viewer-header__actions > .hm-sw-viewer-status { padding-inline: 12px; }
/* Icon buttons in the strip (e.g. 정보 / license, 2026-10-21 final): 32px wide, full strip height, the strip face but no
line around the button in any state (no border, no side / top / bottom lines). Keyboard focus keeps its outline. */
.hm-sw-viewer-header .hm-sw-viewer-header__actions > .hm-sw-viewer-header__button {
/* 2026-10-23: no border box at all (was a transparent 1px border): the strip outline (::after, inset 0) is placed from
the padding box, so a button border moved it inward and drew a line around the button. Same 32px box. */
border-width: 0;
/* No line at all on the button (2026-10-21 final): same 48px box and edges as minimize / close, the strip face only. */
box-shadow: none;
}
/* Rounded end of the menu surface before the strip (2026-10-21 user request, as SWHeader: object area radius 6px,
2px header gap, then the window area). The first strip segment paints, just left of itself and over the object
border band, the header background (gap + the corners outside the radius) and on top the surface end: the same
object face (a vertical gradient, so the copy lines up) and border with the right radius. The 8px it covers are
the empty group padding + gap; below 1180px (2px each) the segment keeps 4px more room. Heights are unchanged. */
/* 2026-10-23: the first segment's left side is the strip's outer gradient line, painted inside it (a 1px layer in place
of the flat divider, so its width is unchanged). */
.hm-sw-viewer-header .hm-sw-viewer-header__actions > :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons):not(:is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons) + *) {
background: var(--hm-sw-header-document-border-gradient) left top / 1px 100% no-repeat border-box, var(--hm-sw-header-document-background);
box-shadow: none;
}
/* The empty strip-start mark (SWViewerHeader, right before `trailing`) carries the surface end, so the first segment
keeps its ::after for the strip outline. It is a 0-wide stretch item at the segment's left edge (its negative margin
takes back the actions gap it adds), so the end keeps the exact place, size and 1px-outset height it had as the
first segment's ::before / ::after. */
.hm-sw-viewer-header__strip-start { position: relative; flex: 0 0 0; align-self: stretch; width: 0; margin-right: calc(-1 * var(--hm-sw-viewer-gap)); pointer-events: none; }
.hm-sw-viewer-header__strip-start:has(+ :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons))::before,
.hm-sw-viewer-header__strip-start:has(+ :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons))::after {
content: "";
position: absolute;
top: calc(-1 * var(--hm-sw-header-object-border-width, 1px));
bottom: calc(-1 * var(--hm-sw-header-object-border-width, 1px));
left: calc(-1 * (var(--hm-sw-header-object-radius) + 2px));
pointer-events: none;
}
.hm-sw-viewer-header__strip-start:has(+ :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons))::before {
width: calc(var(--hm-sw-header-object-radius) + 2px);
background: var(--hm-sw-viewer-background);
}
.hm-sw-viewer-header__strip-start:has(+ :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons))::after {
box-sizing: border-box;
width: var(--hm-sw-header-object-radius);
/* The object surface end: its face and gradient stroke, spanning the same 1px-outset height so both line up. */
border: 1px solid transparent;
border-left: 0;
border-radius: 0 var(--hm-sw-header-object-radius) var(--hm-sw-header-object-radius) 0;
background: var(--hm-sw-header-object-background) padding-box, var(--hm-sw-header-object-border-gradient) border-box;
}
/* No line around the license / info button: the window buttons right after it drop their line before it. */
.hm-sw-viewer-header .hm-sw-viewer-header__actions > .hm-sw-viewer-header__button + .hm-sw-header__window-buttons { box-shadow: 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; }
/* The strip-start mark stays at the first segment's left edge: the 2px gap + its 4px margin below. */
.hm-sw-viewer-header__strip-start { margin-right: -6px; }
.hm-sw-viewer-status { padding-inline: 2px; }
.hm-sw-viewer-header__actions > .hm-sw-viewer-status { padding-inline: 8px; }
.hm-sw-viewer-header .hm-sw-viewer-header__actions > :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons):not(:is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons) + *) { margin-left: 4px; }
.hm-sw-viewer-header__actions > :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons) + :is(.hm-sw-viewer-status, .hm-sw-viewer-header__button, .hm-sw-header__window-buttons) { margin-left: -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-switch-thumb-off); transition: transform 0.15s; }
.hm-sw-viewer-switch[data-state="checked"] { background: var(--hm-sw-viewer-switch-on); }
.hm-sw-viewer-switch[data-state="checked"] .hm-sw-viewer-switch__thumb { transform: translateX(16px); background: var(--hm-sw-viewer-switch-thumb-on); }
.hm-sw-theme .hm-sw-viewer-switch:disabled { opacity: var(--hm-sw-viewer-disabled-opacity); cursor: not-allowed; }
/* Panel switches: the SW popup toggle face in sw.css (Figma toggle_btn_new, 2026-10-22). */
@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; }
/* Bottom gutter outside the scrollport (2026-10-22, user-set 8px): the SWPopup body's 7px bottom padding is inside the
scroll area, so scrolled rows ran into it up to the frame border. A transparent border instead clips the list
8px above the frame border. */
.hm-sw-viewer-panel .hm-sw-property__body { padding-bottom: 0; border-bottom: 8px solid transparent; }
.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; }
/* 2026-10-23 (user request): a card (grouped) Section takes no top margin, so a consumer's "next group" spacing
class does not add to the panel body gap; plain Sections keep theirs. */
.hm-sw-viewer-section[data-surface="card"] {
margin-top: 0;
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; }
/* 2026-10-22 (user request): value inputs (number, text such as 하이퍼링크) take the property window field
(SW/Popup › Property Panel): transparent 1px border, radius 2, 7px inset, 14px 500 #E60403 value; Hover /
editing rgba(33,29,19,.4) border, editing #0F0D0A with the black text outline. Width / height and the layer
search box are unchanged. Read-only values keep the label color and the keyboard focus ring. */
.hm-sw-theme .hm-sw-viewer-input:not([type="search"]) {
padding: 0 7px;
border-color: transparent;
border-radius: 2px;
background: transparent;
color: var(--hm-sw-header-input-color);
caret-color: var(--hm-sw-header-input-color);
font-size: 14px;
font-weight: 500;
line-height: 16px;
letter-spacing: 0.02em;
appearance: textfield;
}
.hm-sw-theme .hm-sw-viewer-input:not([type="search"])::-webkit-inner-spin-button,
.hm-sw-theme .hm-sw-viewer-input:not([type="search"])::-webkit-outer-spin-button { appearance: none; margin: 0; }
.hm-sw-theme .hm-sw-viewer-input:not([type="search"]):is(:hover:not(:disabled, :read-only), :focus:not(:read-only)) { border-color: var(--hm-sw-property-field-hover-border-color); }
.hm-sw-theme .hm-sw-viewer-input:not([type="search"]):focus:not(:read-only) { outline: none; background: var(--hm-sw-property-field-editing-background); text-shadow: var(--hm-sw-header-text-outline); }
/* A field unit (px/mm) sits inside the value box like the property window unit: the control row is the box (same
80px for the input alone) and the editing face covers the unit, which turns #FFF on it. */
.hm-sw-theme .hm-sw-viewer-field__control:has(> .hm-sw-viewer-input:not([type="search"]) + .hm-sw-viewer-field__unit) {
box-sizing: border-box;
height: 28px;
padding: 0 7px;
border: 1px solid transparent;
border-radius: 2px;
}
.hm-sw-theme .hm-sw-viewer-field__control:has(> .hm-sw-viewer-field__unit) > .hm-sw-viewer-input:not([type="search"]) {
width: 64px;
height: 26px;
padding: 0;
border: 0;
background: transparent;
}
.hm-sw-theme .hm-sw-viewer-field__control:has(> .hm-sw-viewer-input:not([type="search"], :disabled, :read-only)):is(:hover, :focus-within):has(> .hm-sw-viewer-field__unit) { border-color: var(--hm-sw-property-field-hover-border-color); }
.hm-sw-theme .hm-sw-viewer-field__control:has(> .hm-sw-viewer-input:not([type="search"], :read-only):focus):has(> .hm-sw-viewer-field__unit) { background: var(--hm-sw-property-field-editing-background); }
.hm-sw-theme .hm-sw-viewer-field__control:has(> .hm-sw-viewer-input:not([type="search"], :read-only):focus) > .hm-sw-viewer-field__unit { color: var(--hm-sw-property-field-editing-unit-color); }
.hm-sw-theme .hm-sw-viewer-input:not([type="search"]):read-only { color: var(--hm-sw-property-label); }
.hm-sw-theme .hm-sw-viewer-input:not([type="search"]):read-only:focus-visible { outline: 2px solid var(--hm-sw-property-border); outline-offset: -2px; }
/* 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); }
.hm-sw-property.hm-sw-viewer-panel .hm-sw-select:not(:disabled) { color: var(--hm-sw-select-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%);
}