/* Chrome shared by the scanner's pages and cards. Everything is scoped under `.app`, whose container name the pages' container queries key off; design tokens come from sendou.ink's app/styles/vars.css. */ .app { container: scanner / inline-size; /* the app's own buttons, kept at :where() specificity so any component class overrides it without having to win an ordering race */ & :where(button) { display: inline-flex; align-items: center; justify-content: center; gap: var(--s-1-5); border: var(--border-style-accent); border-radius: var(--radius-field); appearance: none; background: var(--color-text-accent); color: var(--color-text-inverse); cursor: pointer; font-family: inherit; font-size: var(--font-xs); font-weight: var(--weight-bold); padding: 0 var(--field-padding); height: var(--field-size-sm); white-space: nowrap; user-select: none; & > svg { width: 16px; height: 16px; } &:focus-visible { outline: var(--focus-ring); outline-offset: 1px; } &:active { transform: translateY(1px); } &:disabled { cursor: not-allowed; opacity: 0.5; transform: initial; } } } button.outlined { background: transparent; color: var(--color-text-accent); } /* secondary actions live behind this icon-only trigger, pushed to the row's end. Sized explicitly: it is a SendouButton, which brings a competing base look */ button.iconMenu { margin-inline-start: auto; width: var(--field-size-sm); height: var(--field-size-sm); border-radius: var(--radius-field); padding: 0; border: var(--border-style); background: var(--color-bg-higher); color: var(--color-text); &:hover { color: var(--color-text-accent); } & > svg { width: var(--field-size-icon); height: var(--field-size-icon); margin: 0; } } .controls { display: flex; gap: var(--s-2); align-items: center; margin-bottom: var(--s-3); flex-wrap: wrap; } .status { padding: var(--s-0-5) var(--s-3); border-radius: var(--radius-full); font-size: var(--font-2xs); font-weight: var(--weight-bold); border: var(--border-style); } .idle { color: var(--color-text-high); } .watching { color: var(--color-info-high); border-color: var(--color-info-low); background: var(--color-info-low); &::before { content: ""; display: inline-block; width: 7px; height: 7px; border-radius: var(--radius-full); background: currentColor; margin-inline-end: var(--s-1-5); animation: scanner-pulse 1.6s ease-in-out infinite; } } .detected { display: inline-flex; align-items: center; gap: 5px; color: var(--color-success-high); border-color: var(--color-success-low); background: var(--color-success-low); } @keyframes scanner-pulse { 50% { opacity: 0.25; transform: scale(0.8); } } .liveLayout { display: grid; grid-template-columns: minmax(320px, 640px) minmax(0, 1fr); gap: var(--s-4); align-items: start; } .preview { width: 100%; background: #000; border-radius: var(--radius-box); border: var(--border-width) solid var(--color-bg-high); } .feed { display: flex; flex-direction: column; gap: var(--s-3); } .score { color: var(--color-text-high); font-size: var(--font-2xs); } .error { color: var(--color-error); } .dropzone { border: var(--border-width) dashed var(--color-border-high); border-radius: var(--radius-box); padding: var(--s-8); text-align: center; color: var(--color-text-high); font-size: var(--font-sm); font-weight: var(--weight-semi); margin-bottom: var(--s-4); & label { display: inline; font-size: inherit; font-weight: inherit; margin-block-end: 0; text-decoration: underline; cursor: pointer; } } .over { border-color: var(--color-text-accent); color: var(--color-text-accent); } /* a 640px wide preview would starve the feed next to it: split evenly instead */ @container scanner (width < 1000px) { .liveLayout { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } /* the controls wrap here, where a trigger pushed to the end reads as stray */ button.iconMenu { margin-inline-start: 0; } } @container scanner (width < 700px) { .liveLayout { grid-template-columns: minmax(0, 1fr); } /* stacked, the preview would otherwise push the feed off the screen */ .preview { max-height: 45vh; object-fit: contain; } } @media (prefers-reduced-motion: reduce) { .watching::before { animation: none; } }