html, body.dancelooper
{
    height: 100%;
}

body.dancelooper
{
    background: #f4f5f7;
    color: #22252b;
    font-family: arial, helvetica, sans-serif;
    margin: 0;
}

/* Full-bleed: the app fills the whole viewport, no outer gutters. The grid
   below takes all the height the header doesn't use, so the media zone,
   right rail and cue bar are always flush against their edges of the
   window rather than floating inside a centered, padded card. */

.dancelooper-app
{
    height: 100vh;
    box-sizing: border-box;
    padding: 12px 16px;
    display: flex;
    flex-direction: column;
}

.dancelooper-app #dancelooper_header
{
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;
    flex: 0 0 auto;
}

/* Brand mark - logomark image + HTML wordmark (not the PNG wordmark, which
   stays in images/ for future use like social/print where a flat raster is
   actually needed). Embedded here once so it can be reused anywhere else in
   the app later, not just the header. */

.dancelooper-app #dancelooper_header .dancelooper-logomark
{
    height: 40px;
    width: auto;
}

.dancelooper-app #dancelooper_header .dancelooper-wordmark
{
    font-family: 'Fraunces', Georgia, 'Times New Roman', serif;
    font-weight: 600;
    font-size: 34px;
    line-height: 1;
    color: #1D1B16;
    white-space: nowrap;
}

.dancelooper-app #dancelooper_header .dancelooper-wordmark em
{
    font-style: italic;
    color: #C8472F;
}

.dancelooper-app #dancelooper_header .dancelooper-brand
{
    color: #6b7280;
    font-size: 14px;
    align-self: flex-end;
    margin-bottom: 4px;
}

/* Current media indicator, pinned to the right of the header - styled as
   its own pill/chip (background + border + rounded ends), not plain text
   next to the brand line, so it unmistakably reads as a clickable action
   area regardless of whether it lands on the header's first line or wraps
   to its own line below it on a narrow screen. */
.dancelooper-app #dancelooper_header #dancelooper_header_media
{
    position: relative;
    display: flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;
    font-size: 12px;
    font-weight: bold;
    color: #2f4f7a;
    background: #eef4ff;
    border: 1px solid #cfe0fc;
    border-radius: 20px;
    padding: 5px 10px;
    cursor: pointer;
}

.dancelooper-app #dancelooper_header #dancelooper_header_media_name
{
    max-width: 220px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Plain, no box of its own - the whole pill it sits inside already reads as
   the clickable action area, so a second nested button-looking box here
   would just be visual clutter. */
.dancelooper-app #dancelooper_header .dancelooper-change-icon
{
    width: auto;
    flex: 0 0 auto;
    background: none;
    border: none;
    padding: 0;
    margin-bottom: 0;
    font-size: 11px;
    line-height: 1;
    cursor: pointer;
    color: #2f4f7a;
}

.dancelooper-app #dancelooper_header .dancelooper-change-icon svg
{
    width: 12px;
    height: 12px;
    vertical-align: middle;
}

/* Layout: a plain flex row. #dancelooper_main (top/center/bottom stacked) grows to
   fill the space; #dancelooper_right is a fixed-width rail. Flex's default
   align-items:stretch makes both columns match height automatically, with no
   row-track math to get wrong - this replaced an earlier CSS-grid version where
   the right rail and the top/bottom strips collapsing via :empty produced a
   mismatched, disconnected box. */

#dancelooper_grid
{
    display: flex;
    gap: 10px;
    flex: 1;
    min-height: 0; /* let this flex row actually fill/shrink inside the column above */
}

#dancelooper_main
{
    flex: 1;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/* Shrink-wraps to its own content (shortcut labels, buttons) instead of a
   forced fixed width, so the media zone reclaims whatever the rail doesn't
   need and auto-fills the rest of the screen. */

#dancelooper_right
{
    flex: 0 0 auto;
    width: max-content;
    background: #ffffff;
    border: 1px solid #d8dbe2;
    border-radius: 6px;
    padding: 8px;
    font-size: 11px;
    /* no overflow:hidden - hover tooltips need to spill outside this narrow rail */
    /* Positioned with a z-index so whatever the rail grows or spills over
       (the video, and the YouTube iframe in particular) paints BELOW it -
       an unpositioned box loses to an iframe. Under the banner (1000) and
       the modals (9999). */
    position: relative;
    z-index: 30;
}

@media (max-width: 820px)
{
    #dancelooper_grid
    {
        flex-direction: column;
    }

    /* Smaller logo/wordmark/brand so "DanceLooper" and "by Studio Mastery
       Builder" fit on the header's first line together instead of the
       brand text alone forcing a wrap - the full-size 34px wordmark alone
       already spans a phone-width screen. */
    .dancelooper-app #dancelooper_header .dancelooper-logomark
    {
        height: 26px;
    }

    .dancelooper-app #dancelooper_header .dancelooper-wordmark
    {
        font-size: 20px;
    }

    .dancelooper-app #dancelooper_header .dancelooper-brand
    {
        font-size: 12px;
        margin-bottom: 2px;
    }

    .dancelooper-app #dancelooper_header
    {
        gap: 8px;
    }

    /* The right rail drops below the video at this width instead of
       sitting in a narrow side column - its action buttons need to be
       properly tappable, not just readable, once that happens. */
    #dancelooper_right .dancelooper-shortcut-action
    {
        padding: 10px 12px;
        font-size: 15px;
        border-radius: 6px;
    }

    #dancelooper_right .dancelooper-shortcut-key
    {
        font-size: 12px;
        padding: 3px 6px;
    }

    #dancelooper_right .dancelooper-shortcut-list li
    {
        gap: 4px;
        padding: 6px 0;
    }

    /* The media indicator (#dancelooper_header_media) already wraps onto
       its own line once the header runs out of room (flex-wrap on
       #dancelooper_header) - margin-left:auto (inherited from the base
       rule) keeps it pinned to the right on that line too, same as it does
       sharing a line with the logo. */
    .dancelooper-app #dancelooper_header #dancelooper_header_media
    {
        font-size: 16px;
        padding: 9px 14px;
        gap: 8px;
    }

    .dancelooper-app #dancelooper_header #dancelooper_header_media_name
    {
        max-width: 55vw;
    }

    .dancelooper-app #dancelooper_header .dancelooper-change-icon svg
    {
        width: 16px;
        height: 16px;
    }

    /* The pill stays right-aligned (see above), so the tip keeps its base
       right:0 anchor, growing leftward from the pill's right edge same as
       always - just capped to the viewport width as a hard safety net so
       it can never overhang the left edge regardless of exactly how narrow
       the screen is. */
    .dancelooper-app #dancelooper_header .dancelooper-tip-header
    {
        max-width: calc(100vw - 32px);
    }

    /* Device gear, keyboard toggle and Add Pedal all get the same bigger,
       labeled treatment as data-emphasize="1" gives the keyboard toggle
       with no device active - unconditionally here, since a small square
       icon with only a hover tooltip isn't a real tap target on mobile. */
    #dancelooper_device_gear_icon,
    #dancelooper_keyboard_toggle_icon,
    #dancelooper_device_add_pedal_icon
    {
        width: auto;
        height: auto;
        padding: 8px 14px;
    }

    #dancelooper_device_gear_icon .dancelooper-icon-button-label,
    #dancelooper_keyboard_toggle_icon .dancelooper-icon-button-label,
    #dancelooper_device_add_pedal_icon .dancelooper-icon-button-label
    {
        display: inline;
    }

    /* Labeled unconditionally here regardless of data-emphasize - same
       "don't also show a redundant hover tooltip" reasoning applies. */
    #dancelooper_device_gear_icon:hover::after,
    #dancelooper_keyboard_toggle_icon:hover::after,
    #dancelooper_device_add_pedal_icon:hover::after
    {
        display: none;
    }
}

/* Shared surfaces */

#dancelooper_top,
#dancelooper_bottom
{
    background: #ffffff;
    border: 1px solid #d8dbe2;
    border-radius: 6px;
    padding: 10px 12px;
}

#dancelooper_center
{
    background: #ffffff;
    border: 1px solid #d8dbe2;
    border-radius: 6px;
    padding: 14px;
    flex: 1;
    min-height: 0;
    display: flex;
}

/* Top: current media name + switch dropdown */

#dancelooper_top
{
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}

#dancelooper_top select
{
    flex: 1 1 260px;
}

/* Center: the media zone. Fills the whole card - a dashed accent frame + icon
   stand in for a text label rather than a "Media" heading. */

#dancelooper_center .dancelooper-media-zone
{
    position: relative;
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 16px;
    padding: 20px;
    border: 2px dashed #c7cddb;
    border-radius: 10px;
    overflow: hidden;
}

#dancelooper_center .dancelooper-media-zone .dancelooper-tip
{
    max-width: 320px;
}

/* Large faded logomark watermark, purely decorative, sits behind the
   icon/button/cards while no media is loaded (or being loaded). */
#dancelooper_center .dancelooper-media-zone::before
{
    content: '';
    position: absolute;
    inset: 0;
    background-image: url(/images/dancelooper-logo-mark.png);
    background-repeat: no-repeat;
    background-position: center;
    background-size: min(70%, 520px);
    opacity: 0.05;
    z-index: -1;
    pointer-events: none;
}

#dancelooper_center .dancelooper-media-zone svg
{
    width: 56px;
    height: 56px;
    color: #2f6fed;
    opacity: 0.55;
}

#dancelooper_center button.dancelooper-cta
{
    font-size: 17px;
    padding: 16px 32px;
    background: #2f6fed;
    color: #fff;
    border: none;
    border-radius: 6px;
    cursor: pointer;
}

#dancelooper_center .dancelooper-media-zone ul
{
    list-style: none;
    margin: 0;
    padding: 0;
    width: 100%;
    max-width: 420px;
}

#dancelooper_center .dancelooper-media-zone li
{
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: 4px;
    background: #f4f5f7;
    margin-bottom: 6px;
}

#dancelooper_center .dancelooper-media-zone li a
{
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

#dancelooper_center .dancelooper-media-zone .dancelooper-media-meta
{
    flex: 0 0 auto;
    font-size: 12px;
    color: #6b7280;
    white-space: nowrap;
}

#dancelooper_center .dancelooper-media-zone .dancelooper-media-delete
{
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    padding: 0;
    background: none;
    border: none;
    border-radius: 50%;
    color: #6b7280;
    font-size: 16px;
    line-height: 1;
    cursor: pointer;
}

#dancelooper_center .dancelooper-media-zone .dancelooper-media-delete:hover
{
    background: #fde8e8;
    color: #c0392b;
}

/* Load-media cards: replaces the plain button once "Load Media" is clicked.
   Two large, purpose-built, mutually-exclusive choices, not a stacked form. */

#dancelooper_center .dancelooper-load-cards
{
    display: flex;
    gap: 14px;
    flex-wrap: wrap;
    justify-content: center;
    width: 100%;
    max-width: 480px;
}

#dancelooper_center .dancelooper-load-card
{
    flex: 1 1 190px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 26px 16px;
    background: #f7f9fc;
    border: 1px solid #d8dbe2;
    border-radius: 10px;
    cursor: pointer;
    color: #22252b;
    font-size: 15px;
    font-weight: bold;
}

#dancelooper_center .dancelooper-load-card:hover
{
    border-color: #2f6fed;
    background: #eef3ff;
}

#dancelooper_center .dancelooper-load-card svg
{
    width: 34px;
    height: 34px;
    color: #2f6fed;
}

#dancelooper_center .dancelooper-load-card input[type=text]
{
    width: 100%;
    box-sizing: border-box;
    font-weight: normal;
    font-size: 13px;
    padding: 8px;
    border: 1px solid #c7cddb;
    border-radius: 4px;
}

#dancelooper_center .dancelooper-load-card button.dancelooper-load-confirm
{
    width: 100%;
    padding: 8px;
    background: #2f6fed;
    color: #fff;
    border: none;
    border-radius: 4px;
    font-weight: bold;
    cursor: pointer;
}

#dancelooper_center .dancelooper-load-cancel
{
    background: none;
    border: none;
    color: #6b7280;
    text-decoration: underline;
    cursor: pointer;
    font-size: 13px;
    width: 100%;
    text-align: center;
}

#dancelooper_center .dancelooper-media-error
{
    color: #b3261e;
    font-size: 13px;
}

#dancelooper_center .dancelooper-error-box
{
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    text-align: center;
}

#dancelooper_center video
{
    width: 100%;
    min-height: 0;
    max-height: 100%;
    object-fit: contain;
    border-radius: 4px;
    background: #000;
}

#dancelooper_center #dancelooper_youtube_target
{
    width: auto;
    height: 100%;
    max-width: 100%;
    min-height: 0;
    aspect-ratio: 16 / 9;
}

/* Right: the always-on control rail. Icon-first, compact, no scrolling. */

#dancelooper_right .dancelooper-shortcut-list
{
    list-style: none;
    margin: 0 0 10px 0;
    padding: 0;
}

/* Stacked, not side-by-side - the action on its own line, and below it a
   key line that can carry up to two trigger sources ("Pedal #2 / Space")
   now that Keyboard and a pedal device can both be bound to the same
   action at once. */
#dancelooper_right .dancelooper-shortcut-list li
{
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    padding: 3px 0;
}

/* Action leads (left, forms a clean column); key/trigger trails (right).
   A real button, not plain text - every shortcut is clickable (with or
   without a device selected), so it needs to look pressable at a glance. */
#dancelooper_right .dancelooper-shortcut-action
{
    width: auto;
    flex: 1;
    text-align: left;
    background: #f4f5f7;
    border: 1px solid #d8dbe2;
    border-radius: 3px;
    padding: 3px 6px;
    margin-bottom: 0;
    font-size: 12px;
    font-weight: bold;
    color: #22252b;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    cursor: pointer;
}

#dancelooper_right .dancelooper-shortcut-action:hover
{
    border-color: #2f6fed;
    color: #2f6fed;
}

/* Disabled while a range is actively being set - nothing should interfere
   with it until Set Range End (or the hover's Click to set range end). */
#dancelooper_right .dancelooper-shortcut-action:disabled
{
    opacity: 0.4;
    cursor: not-allowed;
}

#dancelooper_right .dancelooper-shortcut-action:disabled:hover
{
    border-color: #d8dbe2;
    color: #22252b;
}

/* Rail sections - Playhead (where you are) and Range (what you loop) each
   get a header, and range rows carry the same blue as the range's fill on
   the timeline so the two never read as the same kind of control. */
#dancelooper_right .dancelooper-shortcut-section
{
    margin-top: 6px;
    padding: 2px 0 2px 6px;
    font-size: 10px;
    font-weight: bold;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #6b7280;
    border-left: 3px solid #b8bec9;
}

#dancelooper_right .dancelooper-shortcut-section[data-section="range"]
{
    color: #2f6fed;
    border-left-color: #2f6fed;
}

#dancelooper_right .dancelooper-shortcut-icon
{
    display: inline-block;
    min-width: 30px;
    margin-right: 4px;
    font-family: monospace;
    font-weight: normal;
    color: #6b7280;
}

#dancelooper_right .dancelooper-shortcut-row[data-section="range"] .dancelooper-shortcut-icon
{
    color: #2f6fed;
}

/* Every range row (header, delay, the range actions) shares one continuous
   blue left bar and faint tint - li has no margin, only 3px of vertical
   padding, so the background runs unbroken from the header down - matching
   the range group on the timeline's playhead box. */
#dancelooper_right .dancelooper-shortcut-list li[data-section="range"]
{
    border-left: 3px solid #2f6fed;
    background: rgba(47, 111, 237, 0.08);
    padding-left: 6px;
    padding-right: 4px;
}

/* Controls rows (the playhead's own actions) get the same continuous bar as
   the range rows, in gray - header and rows read as one block. */
#dancelooper_right .dancelooper-shortcut-list li[data-section="playhead"]
{
    border-left: 3px solid #b8bec9;
    background: rgba(107, 114, 128, 0.08);
    padding-left: 6px;
    padding-right: 4px;
}

#dancelooper_right .dancelooper-shortcut-delay
{
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
}

#dancelooper_right .dancelooper-shortcut-delay-label
{
    font-size: 12px;
    font-weight: bold;
    color: #22252b;
    white-space: nowrap;
}

#dancelooper_right .dancelooper-shortcut-delay .dancelooper-shortcut-icon
{
    color: #b7791f;
}

#dancelooper_right .dancelooper-shortcut-delay-controls
{
    display: flex;
    align-items: center;
    gap: 4px;
}

#dancelooper_right .dancelooper-shortcut-delay-controls button
{
    width: 22px;
    min-height: 22px;
    padding: 0;
    margin-bottom: 0;
    background: #f0b93d;
    border: none;
    border-radius: 4px;
    color: #22252b;
    font-weight: bold;
    cursor: pointer;
}

#dancelooper_right .dancelooper-shortcut-delay-controls button:disabled
{
    opacity: 0.4;
    cursor: not-allowed;
}

#dancelooper_right .dancelooper-shortcut-delay-value
{
    min-width: 40px;
    padding: 2px 0;
    border-radius: 4px;
    text-align: center;
    font-size: 12px;
    font-weight: bold;
    font-variant-numeric: tabular-nums;
    color: #b7791f;
}

#dancelooper_right .dancelooper-shortcut-delay-value.dancelooper-shortcut-delay-counting
{
    background: #f0b93d;
    color: #22252b;
}

#dancelooper_right .dancelooper-shortcut-key
{
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 4px;
    flex-wrap: wrap;
    font-size: 10px;
    white-space: nowrap;
}

/* A keyboard key reads as an actual keycap - bordered box, monospace, a
   heavier bottom edge suggesting it's raised off the row - a pedal reads as
   a rounded device badge instead, since it's a label ("Pedal #1"), not a
   literal keystroke. Different shapes so the trigger type is obvious at a
   glance, not just different text that happens to say "Pedal" or not. */
#dancelooper_right .dancelooper-shortcut-key-part
{
    padding: 1px 5px;
    white-space: nowrap;
}

#dancelooper_right .dancelooper-shortcut-key-part[data-source="keyboard"]
{
    font-family: monospace;
    background: #fff;
    border: 1px solid #c7cdd6;
    border-bottom-width: 2px;
    border-radius: 3px;
    color: #22252b;
}

#dancelooper_right .dancelooper-shortcut-key-part[data-source="pedal"]
{
    background: #eef4ff;
    border: 1px solid #cfe0fc;
    border-radius: 9px;
    color: #2f4f7a;
    font-weight: bold;
}

/* Play/Pause swaps purely via CSS off body[data-status], set once per
   loop_tick() poll - no re-render of the shortcuts list needed just because
   playback started or stopped. */
#dancelooper_right .dancelooper-label-pause
{
    display: none;
}

body[data-status="playing"] #dancelooper_right .dancelooper-label-play
{
    display: none;
}

body[data-status="playing"] #dancelooper_right .dancelooper-label-pause
{
    display: inline;
}

#dancelooper_right hr
{
    border: none;
    border-top: 1px solid #eef0f3;
    margin: 8px 0;
}

#dancelooper_right .dancelooper-status-dot
{
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #999;
    display: inline-block;
    margin-right: 4px;
}

#dancelooper_right .dancelooper-status-dot[data-on="1"]
{
    background: #2f9e52;
}

#dancelooper_right .dancelooper-device-status
{
    margin-bottom: 6px;
    font-size: 12px;
    font-weight: bold;
}

/* Visible flag when a device failed to load cleanly and got fields reset to
   defaults - title attribute carries the specifics, logged in full to the
   console. Not something that just silently happens. */
#dancelooper_right .dancelooper-device-warning
{
    color: #b3261e;
    font-weight: normal;
    cursor: help;
    margin-left: 4px;
}

/* Editing state: same tint as the working area below, so it reads as part
   of the same editing surface even though it's a separate element. */
#dancelooper_right .dancelooper-device-status.dancelooper-editing
{
    background: #eef3ff;
    border: 1px solid #cfe0fc;
    border-radius: 4px;
    padding: 3px 5px;
    margin: -3px -5px 6px -5px;
}

/* Same font/size/weight as the label it replaces, so it's clearly an
   in-place edit of that text, not a different kind of field. */
#dancelooper_right #dancelooper_device_name_input
{
    font-size: 12px;
    font-weight: bold;
    font-family: inherit;
    border: 1px solid #2f6fed;
    border-radius: 3px;
    padding: 1px 4px;
    width: auto;
}

/* Device header: the "+" (add device) icon pinned top-right of the rail. */

#dancelooper_device_header
{
    display: flex;
    justify-content: flex-end;
    margin-bottom: 4px;
}

/* Icon buttons (add / edit / switch) - compact, tooltip on hover instead of a
   text label, so the rail stays slim regardless of how many devices exist. */

.dancelooper-icon-button
{
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 26px;
    height: 26px;
    padding: 4px;
    background: #f4f5f7;
    border: 1px solid #d8dbe2;
    border-radius: 5px;
    color: #4b5563;
    cursor: pointer;
    box-sizing: border-box;
}

.dancelooper-icon-button svg
{
    width: 18px;
    height: 18px;
    flex-shrink: 0;
}

.dancelooper-icon-button:hover
{
    border-color: #2f6fed;
    color: #2f6fed;
}

/* Hidden by default (icon-only) - shown, alongside a bigger pill-shaped
   button instead of a small square, either when JS marks a button
   data-emphasize="1" (e.g. the keyboard toggle with no pedal active) or
   unconditionally on mobile (see the @media rule further down), where
   every one of these three top-bar buttons needs to read as a real,
   properly-sized tap target instead of a small glyph. */
.dancelooper-icon-button-label
{
    display: none;
    font-size: 12px;
    font-weight: bold;
    white-space: nowrap;
}

.dancelooper-icon-button[data-emphasize="1"]
{
    width: auto;
    height: auto;
    padding: 8px 14px;
    /* Inside a flex row (e.g. #dancelooper_setup_top_row's space-between),
       a flex item's default flex-shrink:1 can compress it below its own
       label's width if the row runs tight - the box visibly shrinks but
       the nowrap text inside doesn't, so it spills out past the button's
       own border ("Detach from Dev|ice" cut off mid-word). This button
       needs to stay at its full labeled width regardless of what else is
       sharing the row with it. */
    flex-shrink: 0;
}

.dancelooper-icon-button[data-emphasize="1"] .dancelooper-icon-button-label
{
    display: inline;
}

/* Draws the eye to the gear when the device isn't actually ready yet - at
   least one button still needs a keystroke connected. */
.dancelooper-icon-button-attention
{
    background: #fffaf0;
    border-color: #f0c36d;
    color: #b7791f;
}

/* "On" look shared by the device gear (a device is active) and the
   keyboard toggle (enabled) - blue like other active/selected states in
   this app, distinct from the amber "needs attention" style above. */
#dancelooper_device_gear_icon[data-on="1"],
#dancelooper_keyboard_toggle_icon[data-on="1"]
{
    background: #eaf1ff;
    border-color: #2f6fed;
    color: #2f6fed;
}

#dancelooper_right .dancelooper-tip
{
    margin-bottom: 8px;
}

.dancelooper-icon-button[data-tooltip]:hover::after
{
    content: attr(data-tooltip);
    position: absolute;
    top: 50%;
    right: calc(100% + 8px);
    transform: translateY(-50%);
    background: #22252b;
    color: #fff;
    font-size: 11px;
    font-weight: normal;
    white-space: nowrap;
    padding: 3px 7px;
    border-radius: 4px;
    z-index: 1;
}

/* Already showing its own text label - a hover tooltip repeating roughly
   the same thing right next to it just reads as an awkward duplicate. */
.dancelooper-icon-button[data-emphasize="1"][data-tooltip]:hover::after
{
    display: none;
}

#dancelooper_right #dancelooper_device_options
{
    margin-bottom: 6px;
    padding: 6px;
    border: 1px solid #d8dbe2;
    border-radius: 5px;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

#dancelooper_right #dancelooper_device_options p
{
    margin: 0 0 4px 0;
    font-size: 11px;
    font-weight: bold;
    color: #6b7280;
}

#dancelooper_right button.dancelooper-device-option
{
    width: 100%;
    font-size: 11px;
    text-align: left;
    padding: 4px 6px;
    background: #f4f5f7;
    border: 1px solid #d8dbe2;
    border-radius: 4px;
    cursor: pointer;
    color: #22252b;
}

#dancelooper_right button.dancelooper-device-cancel
{
    width: 100%;
    font-size: 11px;
    padding: 3px 2px;
    background: none;
    border: none;
    color: #6b7280;
    text-decoration: underline;
    cursor: pointer;
    margin-top: 2px;
}

/* Rolling activity history - last 10 keydown/keyup/action events, newest on
   top. Each entry fades in briefly, then just sits until it expires (10s,
   handled in JS) or scrolls off past the 10-entry cap. */
#dancelooper_right .dancelooper-debug-log
{
    margin-top: 10px;
    padding-top: 8px;
    border-top: 1px solid #eef0f3;
}

#dancelooper_right .dancelooper-debug-log-title
{
    font-size: 10px;
    font-weight: bold;
    color: #9ca3af;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: 4px;
}

#dancelooper_right .dancelooper-debug-log ul
{
    list-style: none;
    margin: 0;
    padding: 0;
    max-height: 160px;
    overflow-y: auto;
}

#dancelooper_right .dancelooper-debug-log li
{
    font-family: monospace;
    font-size: 10px;
    color: #4b5563;
    padding: 2px 0;
    border-bottom: 1px dotted #eef0f3;
}

/* Action-received indicator - the shortcuts row briefly colors when its
   binding fires, whether from a real press or a mouse click. Hold stays lit
   for as long as it's actually held, not just a brief flash. */
#dancelooper_right .dancelooper-shortcut-flash
{
    background: #eef4ff;
    border-radius: 3px;
}

#dancelooper_right .dancelooper-shortcut-held
{
    background: #fff4e0;
    border-radius: 3px;
}

#dancelooper_right .dancelooper-shortcut-held .dancelooper-shortcut-action
{
    border-color: #f0b93d;
}

/* Tinted background marks this as an active working/editing area, distinct
   from the rest of the rail. */
#dancelooper_right .dancelooper-identify-step
{
    background: #eef3ff;
    border: 1px solid #cfe0fc;
    border-radius: 6px;
    padding: 8px;
    margin-bottom: 6px;
    text-align: center;
}

#dancelooper_right #dancelooper_setup_buttons
{
    text-align: left;
}

/* Back/Switch/Add grouped on the left, Clear Device Selection (an X,
   matching weight/size) alone on the right - mirrored corners, same as
   before switch/add moved in here, just with a left-side group now instead
   of a single icon. */
#dancelooper_right #dancelooper_setup_top_row
{
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 6px;
}

#dancelooper_right #dancelooper_setup_top_row_left
{
    display: flex;
    align-items: center;
    gap: 6px;
}

#dancelooper_right .dancelooper-identify-step p
{
    margin: 0 0 6px 0;
}

#dancelooper_right .dancelooper-identify-step input,
#dancelooper_right .dancelooper-identify-step button
{
    width: 100%;
    box-sizing: border-box;
    margin-bottom: 4px;
    font-size: 11px;
}

/* Icon buttons inside the working area stay compact, not stretched full-width
   like the text inputs/buttons around them. */
#dancelooper_right .dancelooper-identify-step button.dancelooper-icon-button
{
    width: 26px;
    margin-bottom: 6px;
}

/* ...except the labeled ones (Detach from Device: icon + text). The fixed
   26px above out-ranks the base [data-emphasize] rule's width:auto, which left
   this button a small square with its label spilling out both sides - so the
   labeled version is restated here at the same specificity, sized to its
   content and never shrunk below it. */
#dancelooper_right .dancelooper-identify-step button.dancelooper-icon-button[data-emphasize="1"]
{
    width: auto;
    height: auto;
    padding: 8px 14px;
    flex-shrink: 0;
    white-space: nowrap;
}

/* De-emphasized, offset from the real actions above it so it's never an
   easy mis-click - plain text, not a button. */
#dancelooper_right .dancelooper-remove-link
{
    background: none;
    border: none;
    color: #9aa0ae;
    text-decoration: underline;
    text-align: center;
    cursor: pointer;
    margin-top: 14px;
}

#dancelooper_right #dancelooper_setup_button_list
{
    text-align: left;
    margin-bottom: 6px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* Each button gets its own clearly separate, bordered zone: header, connect
   status, the enhanced-detection toggle, then its action rows. */
.dancelooper-button-zone
{
    background: #ffffff;
    border: 1px solid #cfe0fc;
    border-radius: 5px;
    padding: 6px;
}

/* Small differentiation so an unconnected button stands out among its
   already-set-up siblings, instead of only the CTA text saying so. */
.dancelooper-button-zone-unconnected
{
    background: #fffaf0;
    border-color: #f0c36d;
}

.dancelooper-button-zone-header,
.dancelooper-button-zone-status
{
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 4px;
    margin-bottom: 4px;
    font-weight: bold;
}

.dancelooper-button-zone-status
{
    font-weight: normal;
    font-size: 10px;
    color: #4b5563;
}

#dancelooper_right .dancelooper-button-label-input
{
    width: auto;
    flex: 1;
    margin-bottom: 0;
    font-weight: bold;
    font-size: 12px;
    border: 1px solid #2f6fed;
    border-radius: 3px;
    padding: 1px 4px;
}

.dancelooper-button-zone-actions
{
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.dancelooper-button-binding-row
{
    display: flex;
    align-items: center;
    gap: 4px;
}

.dancelooper-button-binding-label
{
    flex: 0 0 90px;
    font-size: 10px;
    color: #4b5563;
    white-space: nowrap;
}

.dancelooper-button-binding-summary
{
    flex: 1;
    font-size: 10px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

#dancelooper_right .dancelooper-button-binding-row select,
#dancelooper_right .dancelooper-button-binding-row input
{
    width: auto;
    flex: 1;
    margin: 0;
    padding: 1px 2px;
    box-sizing: border-box;
    font-size: 10px;
    text-align: left;
}

/* Editing a binding shows three stacked pickers (Pre/Action/Post) instead
   of one - narrower inner labels than the outer row's, since "Pre"/"Post"
   are short and the rail is narrow. */
.dancelooper-button-binding-edit
{
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.dancelooper-button-binding-edit .dancelooper-button-binding-label
{
    flex: 0 0 34px;
}

/* Small, lighter-weight than a normal button - a plain link for
   secondary actions (connect/reconnect, remove-while-listening). */
#dancelooper_right .dancelooper-lighter-link
{
    width: auto;
    background: none;
    border: none;
    color: #6b7280;
    text-decoration: underline;
    font-size: 10px;
    cursor: pointer;
    margin-bottom: 0;
    padding: 0;
}

#dancelooper_right .dancelooper-lighter-link:hover
{
    color: #2f6fed;
}

/* Full-row CTA for the one thing on an unconnected row that actually needs
   attention - same blue as the big media-zone CTA, scaled down to the
   rail's 10px baseline instead of #dancelooper_center's larger one. Takes
   the whole row (no "Button" label sharing it) so its text never overflows. */
#dancelooper_right .dancelooper-cta
{
    width: 100%;
    flex: 1;
    box-sizing: border-box;
    background: #2f6fed;
    color: #fff;
    border: none;
    border-radius: 3px;
    padding: 3px 8px;
    margin-bottom: 0;
    font-size: 10px;
    text-align: center;
    cursor: pointer;
}

/* Dismissible tips - shared look wherever a first-time-user nudge shows
   (header media, empty media list, no pedal device, no cues yet). Only
   positioning differs per spot, handled by each container's own rule. */
.dancelooper-tip
{
    display: flex;
    align-items: center;
    gap: 6px;
    background: #eef4ff;
    border: 1px solid #cfe0fc;
    border-radius: 4px;
    padding: 4px 8px;
    font-size: 11px;
    color: #2f4f7a;
    text-align: left;
}

.dancelooper-tip-icon
{
    flex: 0 0 auto;
    width: 14px;
    height: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: #2f6fed;
    color: #fff;
    font-size: 10px;
    font-style: italic;
    font-family: Georgia, 'Times New Roman', serif;
}

.dancelooper-tip-text
{
    flex: 1;
}

/* Small inline copy of a real control's icon, embedded in a tip's text so
   it visually points at exactly the button it's describing. */
.dancelooper-tip-icon-inline
{
    display: inline-flex;
    vertical-align: middle;
    width: 12px;
    height: 12px;
    margin: 0 2px;
}

.dancelooper-tip-icon-inline svg
{
    width: 100%;
    height: 100%;
}

.dancelooper-tip-dismiss
{
    flex: 0 0 auto;
    width: auto;
    background: none;
    border: none;
    color: #6b7280;
    font-size: 13px;
    line-height: 1;
    cursor: pointer;
    padding: 0;
    margin: 0;
}

.dancelooper-tip-dismiss:hover
{
    color: #c0392b;
}

/* Header's tip hangs below the media indicator, same anchoring as the
   flyout, since the header row itself has no room to grow. It's a
   descendant of the same element the flyout hovers off of, so moving the
   mouse onto the tip to click its dismiss (x) keeps the flyout's hover
   active too - z-index above the flyout's (20) so the tip (and its x)
   still render on top instead of getting covered by it. */
.dancelooper-app #dancelooper_header .dancelooper-tip-header
{
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: 4px;
    width: 220px;
    z-index: 25;
}


/* Bottom: cue bar */

#dancelooper_bottom
{
    display: block;
    font-size: 14px;
}

#dancelooper_bottom .dancelooper-cue-timeline-bound
{
    flex: 0 0 auto;
    font-size: 11px;
    color: #6b7280;
    white-space: nowrap;
}

#dancelooper_bottom .dancelooper-cue-timeline-rows
{
    list-style: none;
    margin: 4px 0 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

#dancelooper_bottom .dancelooper-cue-timeline-row
{
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* The control box, fixed and centered on its own line above the track. */
#dancelooper_bottom .dancelooper-cue-timeline-playhead-panel
{
    order: -1;
    flex: 0 0 100%;
    display: flex;
    justify-content: center;
    margin-bottom: 4px;
}


#dancelooper_bottom .dancelooper-cue-select
{
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    background: #f4f5f7;
    border: 1px solid #d8dbe2;
    border-radius: 50%;
    color: #9ca3af;
    font-size: 12px;
    line-height: 1;
    cursor: pointer;
}

#dancelooper_bottom .dancelooper-cue-timeline-track
{
    position: relative;
    flex: 1;
    height: 14px;
    background: #eef0f3;
    border-radius: 3px;
    cursor: pointer;
    /* Clicking to seek reads as a drag across text (the playhead's own
       status/numbers lines) to the browser - this stops it starting a text
       selection instead of just seeking. */
    -webkit-user-select: none;
    user-select: none;
}

#dancelooper_bottom .dancelooper-cue-timeline-fill
{
    position: absolute;
    top: 0;
    height: 100%;
    background: #2f6fed;
    border-radius: 3px;
    opacity: 0.6;
}

#dancelooper_bottom .dancelooper-cue-timeline-row-selected .dancelooper-cue-timeline-fill
{
    opacity: 1;
}

/* The growing fill pulses while its cue is mid-marking, so it reads as
   "actively recording" rather than just a bar that happens to be moving. */
#dancelooper_bottom .dancelooper-cue-timeline-row-marking .dancelooper-cue-timeline-fill
{
    background: #f0b93d;
    animation: dancelooper-cue-marking-pulse 1s ease-in-out infinite;
}

@keyframes dancelooper-cue-marking-pulse
{
    0%, 100% { opacity: 0.5; }
    50% { opacity: 1; }
}

/* Playing/seek indicator - a line tracking the actual playhead (moved every
   loop_tick()), with a tag above it always explaining the context at that
   position: setting the range, playing inside it, or playing the full
   video outside it. Sits above the track itself, in the same 20px of
   headroom the hover box's arrow already assumes is clear. */
#dancelooper_bottom .dancelooper-cue-timeline-playhead
{
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    pointer-events: none;
    z-index: 5;
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-line
{
    position: absolute;
    top: -3px;
    bottom: -3px;
    left: 0;
    width: 2px;
    background: #22252b;
    transform: translateX(-1px);
}

/* The playhead's control box - one persistent box (its buttons enable/
   disable as playback changes instead of appearing and disappearing, which
   was the blinking), fixed and centered on its own line above the track
   (see .playhead-panel). It does NOT follow the playhead any more - only
   the thin line does. Extra right padding clears the [i] info button pinned
   to its top right corner. */
#dancelooper_bottom .dancelooper-cue-timeline-playhead-actions
{
    display: flex;
    position: relative; /* anchors the [i] info button to its own corner */
    width: max-content;
    max-width: 100%;
    flex-direction: row;
    align-items: flex-start;
    gap: 10px;
    background: #22252b;
    border-radius: 4px;
    padding: 8px 34px 8px 10px;
}

/* The playhead's own status + buttons, one column beside the range group. */
/* Same box model as the range group beside it (border, padding, one header
   line, 6px gap, then the button row) - only the border is transparent - so
   both groups' headers and both button rows land on the same lines. */
#dancelooper_bottom .dancelooper-cue-timeline-playhead-group
{
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    padding: 6px 8px;
    border: 1px solid transparent;
    border-left-width: 3px;
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-group .dancelooper-cue-timeline-playhead-paused-label,
#dancelooper_bottom .dancelooper-cue-timeline-playhead-range-group .dancelooper-cue-timeline-playhead-numbers
{
    display: block;
    min-height: 13px;
    line-height: 13px;
}

/* Always ONE line - both groups side by side at every width, never
   stacked and never a button row splitting. Anything that can't fit at full
   size shrinks instead (smaller buttons/padding/gaps below), and long text
   (the status, the range numbers) truncates rather than pushing the box
   wider. min-width:0 all the way down so flex is actually allowed to
   shrink these below their content size. */
#dancelooper_bottom .dancelooper-cue-timeline-playhead-panel
{
    min-width: 0;
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-actions
{
    flex-wrap: nowrap;
    min-width: 0;
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-group,
#dancelooper_bottom .dancelooper-cue-timeline-playhead-range-group
{
    flex: 0 1 auto;
    min-width: 0;
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-button-row .dancelooper-cue-timeline-playhead-icon-button
{
    flex: 0 1 auto;
    min-width: 0;
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-paused-label,
#dancelooper_bottom .dancelooper-cue-timeline-playhead-numbers
{
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
}

@media (max-width: 720px)
{
    #dancelooper_bottom .dancelooper-cue-timeline-playhead-actions
    {
        gap: 6px;
        padding: 6px 30px 6px 6px;
    }

    #dancelooper_bottom .dancelooper-cue-timeline-playhead-actions .dancelooper-cue-timeline-playhead-group,
    #dancelooper_bottom .dancelooper-cue-timeline-playhead-actions .dancelooper-cue-timeline-playhead-range-group
    {
        padding: 4px 5px;
    }

    #dancelooper_bottom .dancelooper-cue-timeline-playhead-actions .dancelooper-cue-timeline-playhead-button-row
    {
        gap: 5px;
    }

    #dancelooper_bottom .dancelooper-cue-timeline-playhead-actions .dancelooper-cue-timeline-playhead-icon-button
    {
        min-height: 34px;
        padding: 6px 8px;
        font-size: 15px;
    }

    #dancelooper_bottom .dancelooper-cue-timeline-playhead-actions .dancelooper-cue-timeline-playhead-info-button
    {
        top: 3px;
        right: 3px;
        width: 22px;
        height: 22px;
        min-width: 22px;
    }
}

@media (max-width: 480px)
{
    #dancelooper_bottom .dancelooper-cue-timeline-playhead-actions .dancelooper-cue-timeline-playhead-button-row
    {
        gap: 3px;
    }

    #dancelooper_bottom .dancelooper-cue-timeline-playhead-actions .dancelooper-cue-timeline-playhead-icon-button
    {
        min-height: 32px;
        padding: 5px 4px;
        font-size: 13px;
    }

    #dancelooper_bottom .dancelooper-cue-timeline-playhead-actions .dancelooper-cue-timeline-playhead-range-group
    {
        column-gap: 4px;
    }
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-icon-button:disabled,
#dancelooper_bottom .dancelooper-cue-timeline-playhead-delay-step:disabled
{
    opacity: 0.35;
    cursor: not-allowed;
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-paused-label
{
    color: #fff;
    font-size: 9px;
    font-weight: bold;
    white-space: nowrap;
}

/* Range start-end, folded into the always-visible tag/actions instead of a
   separate box that only showed on hover. */
#dancelooper_bottom .dancelooper-cue-timeline-playhead-numbers
{
    color: #c6cad3;
    font-size: 9px;
    line-height: 1.4;
    white-space: nowrap;
}

/* The pause before each repeat while looping - a compact stepper, not a
   free-text field, always present here (not just while a delay is running)
   so it can be set up before ever pressing play. */
#dancelooper_bottom .dancelooper-cue-timeline-playhead-range-group .dancelooper-cue-timeline-playhead-numbers
{
    grid-area: numbers;
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-range-group .dancelooper-cue-timeline-playhead-button-row
{
    grid-area: buttons;
}

/* Vertical (+ over the number over -), right-aligned in the range group.
   column-reverse so + sits on top without reordering the DOM. */
#dancelooper_bottom .dancelooper-cue-timeline-playhead-delay
{
    grid-area: delay;
    justify-self: end;
    display: flex;
    flex-direction: column-reverse;
    align-items: center;
    gap: 3px;
}

/* The delay's identity color is amber (same one the range-marking pulse
   uses) - always, not just while counting down, so setting it and
   watching it run read as the same thing. The stepper is always amber;
   the "Delay X.X" status text joins it while a countdown is running. */
#dancelooper_bottom .dancelooper-cue-timeline-playhead-delay-step
{
    min-width: 20px;
    min-height: 18px;
    padding: 1px 6px;
    margin-bottom: 0;
    background: #f0b93d;
    border: none;
    border-radius: 4px;
    color: #22252b;
    cursor: pointer;
    font-size: 12px;
    font-weight: bold;
    line-height: 1;
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-delay-step:hover
{
    background: #f7cd6c;
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-delay-value
{
    min-width: 38px;
    padding: 0;
    line-height: 16px;
    border-radius: 4px;
    text-align: center;
    font-size: 11px;
    font-weight: bold;
    font-variant-numeric: tabular-nums;
    color: #f0b93d;
}

/* Counting down: the same number, same spot, same size - just filled solid
   amber so it reads as live, instead of the countdown moving to a status
   line somewhere else. */
#dancelooper_bottom .dancelooper-cue-timeline-playhead-delay-counting .dancelooper-cue-timeline-playhead-delay-value
{
    background: #f0b93d;
    color: #22252b;
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-delaying .dancelooper-cue-timeline-playhead-paused-label
{
    color: #f0b93d;
}

/* Everything belonging to the range - its numbers (the header), the delay
   stepper, the play buttons, Set Range - sits in one bordered panel,
   border tinted the same blue as the range's fill on the track, so it
   reads as one unit distinct from the playhead's own status line above. */
#dancelooper_bottom .dancelooper-cue-timeline-playhead-range-group
{
    display: grid;
    grid-template-columns: auto auto;
    grid-template-areas: "numbers delay" "buttons delay";
    column-gap: 10px;
    row-gap: 6px;
    align-items: start;
    padding: 6px 8px;
    border: 1px solid #2f6fed;
    border-left-width: 3px;
    border-radius: 4px;
    background: rgba(47, 111, 237, 0.10);
}

/* Gap between buttons matters as much as each button's own size for hitting
   the right one on a touch screen - wide enough that adjacent buttons don't
   read as one tap target. */
#dancelooper_bottom .dancelooper-cue-timeline-playhead-button-row
{
    display: flex;
    flex-wrap: nowrap;
    gap: 10px;
}

/* Used both by the paused-actions group and the Setting Range tag's End
   Range button - bigger than the rest of the playhead's text so they read
   as pressable controls, not just more status text, and sized for a
   thumb, not a cursor (min-height ~40px, near the usual mobile tap-target
   floor). Icon on its own, with an inline label span
   (.playhead-button-label) that whoever builds the button shows only when
   it's the only one in its group. */
#dancelooper_bottom .dancelooper-cue-timeline-playhead-icon-button
{
    width: auto;
    min-width: 40px;
    min-height: 40px;
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    background: #f4f5f7;
    border: none;
    border-radius: 6px;
    padding: 10px 16px;
    margin-bottom: 0;
    font-size: 17px;
    line-height: 1.2;
    color: #22252b;
    cursor: pointer;
    white-space: nowrap;
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-icon-button:hover
{
    background: #fff;
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-button-label
{
    font-size: 13px;
    font-weight: bold;
}

/* Circular "i" - pinned to the notification box's own top-right corner
   (the box is position:absolute, which is enough of a containing block for
   this without adding position:relative to it) instead of sitting inline
   with the play buttons, since it explains the group rather than being one
   of its members. Shown instead of inline labels once a group has more
   than one visible button. */
#dancelooper_bottom .dancelooper-cue-timeline-playhead-info-button
{
    position: absolute;
    top: 4px;
    right: 4px;
    width: 26px;
    height: 26px;
    min-width: 26px;
    padding: 0;
    margin-bottom: 0;
    border: none;
    border-radius: 50%;
    background: #2f6fed;
    color: #fff;
    font-size: 13px;
    font-style: italic;
    font-family: Georgia, 'Times New Roman', serif;
    cursor: pointer;
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-info-button:hover
{
    background: #4d84f5;
}

/* Explains a play-button group's icons via a modal instead of cramming
   labels next to every button - lighter than the full-screen capture
   modal since this is just informational, not a blocking prompt. */
.dancelooper-shortcut-info-modal
{
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    z-index: 9999;
    background: rgba(29, 27, 22, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    box-sizing: border-box;
}

.dancelooper-shortcut-info-modal-box
{
    background: #fff;
    border-radius: 8px;
    padding: 16px 20px;
    max-width: 320px;
    width: 100%;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
    box-sizing: border-box;
}

.dancelooper-shortcut-info-modal-title
{
    margin: 0 0 12px 0;
    font-size: 14px;
    font-weight: bold;
    color: #22252b;
}

.dancelooper-shortcut-info-modal-list
{
    list-style: none;
    margin: 0 0 14px 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.dancelooper-shortcut-info-modal-list li
{
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 13px;
    color: #22252b;
}

.dancelooper-shortcut-info-modal-icon
{
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 4px;
    background: #f4f5f7;
    font-size: 14px;
}

.dancelooper-shortcut-info-modal-box .dancelooper-lighter-link
{
    width: auto;
    background: none;
    border: none;
    text-decoration: underline;
    cursor: pointer;
    margin-bottom: 0;
    padding: 0;
    color: #6b7280;
    font-size: 12px;
}

.dancelooper-shortcut-info-modal-box .dancelooper-lighter-link:hover
{
    color: #22252b;
}

#dancelooper_bottom .dancelooper-cue-remove
{
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    padding: 0;
    background: none;
    border: none;
    border-radius: 50%;
    color: #6b7280;
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
}

#dancelooper_bottom .dancelooper-cue-remove:hover
{
    background: #fde8e8;
    color: #c0392b;
}

/* Full-screen capture modal - shown while listening for a key/pedal press,
   so it's unmistakable even if the right rail is scrolled out of view. */
.dancelooper-capture-modal
{
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    z-index: 9999;
    background: rgba(29, 27, 22, 0.92);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 16px;
    text-align: center;
    padding: 16px;
    box-sizing: border-box;
}

.dancelooper-capture-modal p
{
    margin: 0;
}

.dancelooper-capture-modal #dancelooper_capture_modal_title
{
    font-size: 28px;
    font-weight: bold;
    color: #fff;
}

.dancelooper-capture-modal .dancelooper-capture-modal-preview
{
    font-size: 14px;
    color: #cfd3db;
}

#dancelooper_capture_modal_actions
{
    display: flex;
    gap: 20px;
    margin-top: 12px;
}

.dancelooper-capture-modal .dancelooper-lighter-link
{
    width: auto;
    background: none;
    border: none;
    text-decoration: underline;
    cursor: pointer;
    margin-bottom: 0;
    padding: 0;
    color: #cfd3db;
    font-size: 12px;
}

.dancelooper-capture-modal .dancelooper-lighter-link:hover
{
    color: #fff;
}

/* Every action icon (playhead buttons, rail rows, the [i] legend) uses the
   same font stack, so a symbol is drawn identically wherever it appears -
   with the text-presentation selector on the glyphs themselves this keeps
   mobile from falling back to a different (emoji) font per element. */
.dancelooper-cue-timeline-playhead-icon-button,
.dancelooper-shortcut-icon,
.dancelooper-shortcut-info-modal-icon
{
    font-family: "Segoe UI Symbol", "DejaVu Sans", Arial, sans-serif;
}

/* Hero how-to on the Load Media screen: two numbered steps, then a pro-tip
   callout as the third child. */

#dancelooper_center .dancelooper-howto
{
    width: 100%;
    max-width: 480px;
    margin-top: 22px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    text-align: left;
    counter-reset: howto_step;
}

#dancelooper_center .dancelooper-howto > div
{
    position: relative;
    padding: 4px 0 4px 50px;
    min-height: 40px;
}

#dancelooper_center .dancelooper-howto > div:nth-child(-n+2)::before
{
    counter-increment: howto_step;
    content: counter(howto_step);
    position: absolute;
    left: 0;
    top: 2px;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: #2f6fed;
    color: #fff;
    font-size: 18px;
    font-weight: bold;
    line-height: 36px;
    text-align: center;
}

#dancelooper_center .dancelooper-howto > div > div:first-child
{
    color: #22252b;
    font-size: 18px;
    font-weight: bold;
    line-height: 1.3;
}

#dancelooper_center .dancelooper-howto > div > div:last-child
{
    margin-top: 2px;
    color: #4b5563;
    font-size: 14px;
    line-height: 1.45;
}

#dancelooper_center .dancelooper-howto > div:nth-child(3)
{
    margin-top: 6px;
    padding: 12px 14px 12px 50px;
    background: #fff8e6;
    border: 1px solid #f0c36d;
    border-radius: 10px;
}

#dancelooper_center .dancelooper-howto > div:nth-child(3)::before
{
    content: "\1F4A1\FE0E";
    position: absolute;
    left: 14px;
    top: 10px;
    font-size: 24px;
    line-height: 1;
    color: #b7791f;
}

#dancelooper_center .dancelooper-howto > div:nth-child(3) > div:first-child
{
    color: #7a4b00;
}

/* While a range is being set (start marked, end not yet) its numbers are THE
   focus of the playhead box: the range group lights up blue and pulses, the
   numbers go big and bold, and the playhead's own group steps back. The end
   number is live (loop_tick()) - it follows the playhead until the end is set. */
#dancelooper_bottom .dancelooper-cue-timeline-playhead-actions-marking .dancelooper-cue-timeline-playhead-range-group
{
    background: rgba(47, 111, 237, 0.28);
    border-radius: 4px;
    animation: dancelooper-range-focus-pulse 1.2s ease-in-out infinite;
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-actions-marking .dancelooper-cue-timeline-playhead-range-group .dancelooper-cue-timeline-playhead-numbers
{
    min-height: 18px;
    line-height: 18px;
    color: #fff;
    font-size: 14px;
    font-weight: bold;
    font-variant-numeric: tabular-nums;
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-actions-marking .dancelooper-cue-timeline-playhead-group .dancelooper-cue-timeline-playhead-paused-label
{
    min-height: 18px;
    line-height: 18px;
    font-size: 11px;
}

@keyframes dancelooper-range-focus-pulse
{
    0%, 100% { box-shadow: 0 0 0 1px rgba(47, 111, 237, 0.9); }
    50%      { box-shadow: 0 0 0 3px rgba(47, 111, 237, 0.35); }
}

@media (max-width: 480px)
{
    #dancelooper_bottom .dancelooper-cue-timeline-playhead-actions-marking .dancelooper-cue-timeline-playhead-range-group .dancelooper-cue-timeline-playhead-numbers
    {
        font-size: 11px;
    }
}

/* Delay countdown ring: while a delay runs, the playhead's Play/Pause button
   icon turns into a circle that drains as the delay elapses. The (Pause)
   glyph is still in the span - it is only hidden - so the [i] legend and
   screen readers keep reading it. --delay-fraction is set from loop_tick()
   (1 = full, 0 = done); registering it lets the sweep animate smoothly
   between the 150ms ticks. */
@property --delay-fraction
{
    syntax: '<number>';
    inherits: false;
    initial-value: 1;
}

#dancelooper_bottom .dancelooper-cue-timeline-playhead-icon-button > span[data-counting]
{
    display: inline-block;
    width: 1.1em;
    height: 1.1em;
    vertical-align: middle;
    border-radius: 50%;
    background: conic-gradient(#f0b93d calc(var(--delay-fraction) * 360deg), rgba(255, 255, 255, 0.22) 0);
    color: transparent;
    overflow: hidden;
    transition: --delay-fraction 0.15s linear;
}

/* "Not listening" notice: floats above everything while keystrokes are not
   reaching the page (window not focused, tab hidden, or focus inside the
   YouTube iframe). Amber and pulsing so it cannot be mistaken for chrome. */
.dancelooper-focus-banner
{
    position: fixed;
    top: 10px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 1000;
    max-width: calc(100vw - 24px);
    padding: 10px 18px;
    background: #f0b93d;
    color: #22252b;
    border: 2px solid #b7791f;
    border-radius: 8px;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
    font-size: 14px;
    font-weight: bold;
    text-align: center;
    cursor: pointer;
    animation: dancelooper-focus-banner-pulse 1.4s ease-in-out infinite;
}

@keyframes dancelooper-focus-banner-pulse
{
    0%, 100% { box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35), 0 0 0 0 rgba(240, 185, 61, 0.7); }
    50%      { box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35), 0 0 0 8px rgba(240, 185, 61, 0); }
}

/* Portrait / narrow: the rail sits below the video with a full row to spare,
   so the key/pedal triggers go to the RIGHT of each action button instead of
   stacked underneath - one line per action. The button takes what is left
   (and truncates), the triggers keep their size, wrapping only if two of
   them cannot fit side by side. Appended last so it wins over the base
   stacked rule at equal specificity. */
@media (max-width: 820px)
{
    #dancelooper_right .dancelooper-shortcut-list li
    {
        flex-direction: row;
        align-items: center;
        gap: 8px;
    }

    #dancelooper_right .dancelooper-shortcut-list li .dancelooper-shortcut-action
    {
        flex: 1 1 0;
        min-width: 0;
    }

    #dancelooper_right .dancelooper-shortcut-list li .dancelooper-shortcut-key
    {
        flex: 0 1 auto;
        max-width: 55%;
        justify-content: flex-end;
    }
}

/* Touch / narrow screens: iOS (and some Android browsers) zoom the whole page
   in whenever a text field under 16px gets focus, which is also what pushes
   the page sideways afterwards. Every field is 16px here so focusing one never
   zooms (pinch-zoom stays available - the viewport is not locked). Chained
   :not()s and the ids raise specificity above the id-based per-field font
   sizes earlier in this file (10 - 12px). */
@media (pointer: coarse), (max-width: 820px)
{
    .dancelooper-app #dancelooper_right :is(input, select, textarea):not([type=file]):not([type=hidden]),
    .dancelooper-app #dancelooper_center :is(input, select, textarea):not([type=file]):not([type=hidden]),
    .dancelooper-app #dancelooper_right #dancelooper_device_name_input,
    .dancelooper-app #dancelooper_right .dancelooper-button-label-input
    {
        font-size: 16px;
    }
}

/* The rail is width:max-content on desktop; stacked under the video it must
   never be wider than the screen (three stacked binding pickers were enough
   to push it past the edge). */
@media (max-width: 820px)
{
    #dancelooper_right
    {
        width: auto;
        max-width: 100%;
        box-sizing: border-box;
        min-width: 0;
    }
}

/* Mobile: the rail sits under the video, so spend as little height on it as
   possible. The device name moves onto the SAME row as the Keyboard / device
   buttons (name left, buttons right - flex order puts the status before the
   header without touching the markup) and the "Controls" section label is
   dropped (the gray bar still groups its rows). Everything else in the rail
   keeps a full row of its own. */
@media (max-width: 820px)
{
    #dancelooper_right
    {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        column-gap: 8px;
    }

    #dancelooper_right > *
    {
        flex: 0 0 100%;
        min-width: 0;
    }

    #dancelooper_right > #dancelooper_device_status
    {
        order: -1;
        flex: 1 1 0;
        margin-bottom: 4px;
    }

    #dancelooper_right > #dancelooper_device_header
    {
        flex: 0 0 auto;
        margin-bottom: 4px;
    }

    #dancelooper_right .dancelooper-shortcut-section[data-section="playhead"]
    {
        display: none;
    }
}

/* Mobile: the range's Delay row joins the RANGE header on one line (header
   left, delay label + stepper filling the rest) - the list becomes a wrapping
   flex where every row is full width except that header and the delay row
   right after it. The delay row drops its own left bar (the header's bar is
   the one continuous bar) and matches the header's top margin so the two line
   up. */
@media (max-width: 820px)
{
    #dancelooper_right .dancelooper-shortcut-list
    {
        display: flex;
        flex-wrap: wrap;
    }

    #dancelooper_right .dancelooper-shortcut-list > li
    {
        flex: 0 0 100%;
        box-sizing: border-box;
    }

    #dancelooper_right .dancelooper-shortcut-list > li.dancelooper-shortcut-section[data-section="range"]
    {
        flex: 0 0 auto;
        align-self: stretch;
        display: flex;
        align-items: center;
        padding-right: 8px;
    }

    #dancelooper_right .dancelooper-shortcut-list > li.dancelooper-shortcut-delay
    {
        flex: 1 1 0;
        min-width: 0;
        margin-top: 6px;
        border-left: none;
        padding-left: 0;
    }
}

/* Mobile: the Delay row is wide (it shares the RANGE header's line), so
   space-between left it stranded far from its own stepper. The label takes
   the free space and right-aligns instead, sitting against the buttons. */
@media (max-width: 820px)
{
    #dancelooper_right .dancelooper-shortcut-delay .dancelooper-shortcut-delay-label
    {
        flex: 1 1 auto;
        text-align: right;
    }
}

/* Video fills its rounded box: no white padding around the player while a
   local video or YouTube is showing (data-show is set by
   dancelooper_sync_center()); the box's own rounded corners clip it. The
   load cards / error / reattach states keep their padding. */
#dancelooper_center[data-show="video"],
#dancelooper_center[data-show="youtube"]
{
    padding: 0;
    overflow: hidden;
    justify-content: center;
}

#dancelooper_center[data-show="video"] video
{
    border-radius: 0;
}

/* Range bar: less white above (and around) its contents. */
#dancelooper_bottom
{
    padding: 4px 8px;
}

#dancelooper_bottom .dancelooper-cue-timeline-rows
{
    margin-top: 0;
}

/* Portrait: the stacked boxes (video, range bar, rail) touch-close instead of
   floating 10px apart. */
@media (max-width: 820px)
{
    #dancelooper_grid,
    #dancelooper_main
    {
        gap: 4px;
    }
}

/* Portrait: the media chip may grow to 90% of the header width before its
   name is cut off with an ellipsis (it was capped at 55vw), and the chip sits
   closer to the video below it. The name is the flexible part of the chip -
   min-width:0 is what lets it shrink and truncate rather than push the chip
   past the cap. */
@media (max-width: 820px)
{
    .dancelooper-app #dancelooper_header
    {
        row-gap: 4px;
        margin-bottom: 4px;
    }

    .dancelooper-app #dancelooper_header #dancelooper_header_media
    {
        max-width: 90%;
        min-width: 0;
        box-sizing: border-box;
    }

    .dancelooper-app #dancelooper_header #dancelooper_header_media_name
    {
        max-width: none;
        flex: 0 1 auto;
        min-width: 0;
    }
}

/* Portrait rail: no divider line under the device name / buttons, less white
   above and between the rows, and the space that frees goes into the action
   buttons themselves - taller, bigger text, and a raised look (a solid bottom
   edge plus a soft shadow, pressing in on tap) so they read as buttons.
   Disabled ones go flat. */
@media (max-width: 820px)
{
    #dancelooper_right hr
    {
        display: none;
    }

    #dancelooper_right
    {
        padding: 4px 8px 6px 8px;
    }

    #dancelooper_right .dancelooper-shortcut-list li
    {
        padding: 2px 0;
    }

    #dancelooper_right .dancelooper-shortcut-action
    {
        padding: 14px 12px;
        font-size: 17px;
        background: linear-gradient(#ffffff, #eceff4);
        border: 1px solid #c7cdd6;
        border-radius: 8px;
    }

    #dancelooper_right .dancelooper-shortcut-action:not(:disabled)
    {
        box-shadow: 0 2px 0 #b8bec9, 0 4px 8px rgba(0, 0, 0, 0.16);
    }

    #dancelooper_right .dancelooper-shortcut-action:not(:disabled):active
    {
        transform: translateY(2px);
        box-shadow: 0 0 0 #b8bec9, 0 1px 3px rgba(0, 0, 0, 0.2);
    }
}

/* Portrait: the control box spans the whole range bar and its buttons are
   fixed squares (they were being squeezed into narrow tall slivers by the
   shrink-to-fit rules above). The two groups spread to the box's edges; the
   info button stays in the corner. Selectors are one class deeper than the
   720px / 480px shrink blocks so these win at any width. */
@media (max-width: 820px)
{
    #dancelooper_bottom .dancelooper-cue-timeline-playhead-panel .dancelooper-cue-timeline-playhead-actions
    {
        width: 100%;
        max-width: 100%;
        box-sizing: border-box;
        justify-content: space-between;
        padding: 6px 30px 6px 6px;
    }

    #dancelooper_bottom .dancelooper-cue-timeline-playhead-actions .dancelooper-cue-timeline-playhead-button-row .dancelooper-cue-timeline-playhead-icon-button
    {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        flex: 0 0 auto;
        width: 44px;
        height: 44px;
        min-height: 0;
        padding: 0;
        font-size: 18px;
    }
}

@media (max-width: 400px)
{
    #dancelooper_bottom .dancelooper-cue-timeline-playhead-actions .dancelooper-cue-timeline-playhead-button-row .dancelooper-cue-timeline-playhead-icon-button
    {
        width: 40px;
        height: 40px;
        font-size: 16px;
    }
}

/* One trigger (a pedal OR the keyboard) fits to the right of its action, so
   that row is a single line at every screen size: the button takes exactly
   half the row (so every button is the same width instead of each sizing to
   its own label/badge) - never narrower than its own text - and the badge
   sits beside it. Two triggers ("Space / Hold Pedal #1") stay stacked on
   desktop and share the mobile row as before. data-triggers is set in
   dancelooper_sync_shortcuts(). */
#dancelooper_right .dancelooper-shortcut-list li[data-triggers="1"]
{
    flex-direction: row;
    align-items: center;
    gap: 8px;
}

#dancelooper_right .dancelooper-shortcut-list li[data-triggers="1"] .dancelooper-shortcut-action
{
    flex: 0 0 50%;
    min-width: max-content;
    box-sizing: border-box;
}

#dancelooper_right .dancelooper-shortcut-list li[data-triggers="1"] .dancelooper-shortcut-key
{
    flex: 1 1 auto;
    max-width: none;
    justify-content: flex-start;
}

/* Portrait: less padding above and below the label - the row is already tall
   enough from the 17px text. */
@media (max-width: 820px)
{
    #dancelooper_right .dancelooper-shortcut-action
    {
        padding: 9px 12px;
    }
}

/* Welcome splash: full-screen hero over the whole app (above the modals at
   9999), a translucent dark wash so the app shows through behind the card. The
   overlay scrolls if the card is taller than a short screen. Children carry no
   classes - positions inside the card do the styling. */
.dancelooper-splash
{
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 10000;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 16px;
    overflow-y: auto;
    box-sizing: border-box;
    /* Light enough that the app is clearly still there behind the card, so
       this reads as a popup over it, not a separate page. */
    background: rgba(29, 27, 22, 0.5);
    backdrop-filter: blur(2px);
}

.dancelooper-splash .dancelooper-splash-card
{
    width: 100%;
    max-width: 560px;
    margin: auto;
    box-sizing: border-box;
    padding: 28px 24px 22px 24px;
    background: rgba(255, 253, 248, 0.95);
    border-radius: 16px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.5);
    color: #22252b;
    font-size: 16px;
    line-height: 1.5;
}

.dancelooper-splash-card > div:nth-child(1)
{
    text-align: center;
    margin-bottom: 18px;
}

.dancelooper-splash-card > div:nth-child(1) img
{
    display: block;
    height: 72px;
    width: auto;
    margin: 0 auto 6px auto;
}

.dancelooper-splash-card > div:nth-child(1) > div:nth-child(2)
{
    font-family: 'Fraunces', Georgia, 'Times New Roman', serif;
    font-weight: 600;
    font-size: 46px;
    line-height: 1.05;
    color: #1D1B16;
}

.dancelooper-splash-card > div:nth-child(1) em
{
    font-style: italic;
    color: #C8472F;
}

.dancelooper-splash-card > div:nth-child(1) > div:nth-child(3)
{
    margin-top: 6px;
    font-family: 'Fraunces', Georgia, 'Times New Roman', serif;
    font-style: italic;
    font-size: 22px;
    color: #6b7280;
}

.dancelooper-splash-card > div:nth-child(2) > div
{
    margin-bottom: 14px;
}

.dancelooper-splash-card > div:nth-child(2) > div > div:first-child
{
    font-size: 22px;
    font-weight: bold;
    line-height: 1.2;
    color: #1D1B16;
}

.dancelooper-splash-card > div:nth-child(2) > div > div:last-child
{
    margin-top: 2px;
    font-size: 15px;
    color: #4b5563;
}

.dancelooper-splash-card > div:nth-child(2) > div:last-child
{
    margin-bottom: 0;
    text-align: center;
    font-style: italic;
    font-size: 15px;
    color: #6b7280;
}

.dancelooper-splash-card > div:nth-child(5)
{
    margin-top: 16px;
}

.dancelooper-splash-card > div:nth-child(5) > div:first-child
{
    margin-bottom: 8px;
    font-size: 12px;
    font-weight: bold;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: #b7791f;
}

.dancelooper-splash-card > div:nth-child(5) > div:not(:first-child)
{
    margin-bottom: 8px;
    padding: 10px 14px;
    background: #fff8e6;
    border: 1px solid #f0c36d;
    border-radius: 10px;
    font-size: 14px;
}

.dancelooper-splash-card > div:nth-child(5) > div:not(:first-child) > div:first-child
{
    font-size: 16px;
    font-weight: bold;
    color: #7a4b00;
}

.dancelooper-splash-card label
{
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 16px;
    font-size: 15px;
    color: #4b5563;
    cursor: pointer;
}

.dancelooper-splash-card label input
{
    width: 22px;
    height: 22px;
    margin: 0;
    cursor: pointer;
}

.dancelooper-splash-card button
{
    display: block;
    width: 100%;
    margin-top: 14px;
    padding: 14px;
    background: #2f6fed;
    color: #fff;
    border: none;
    border-radius: 10px;
    font-size: 18px;
    font-weight: bold;
    cursor: pointer;
    box-shadow: 0 2px 0 #1f4fb0, 0 4px 10px rgba(47, 111, 237, 0.35);
}

.dancelooper-splash-card button:hover
{
    background: #2560d6;
}

@media (max-width: 480px)
{
    .dancelooper-splash .dancelooper-splash-card
    {
        padding: 20px 16px 16px 16px;
    }

    .dancelooper-splash-card > div:nth-child(1) > div:nth-child(2)
    {
        font-size: 38px;
    }
}

/* The brand in the header reopens the welcome splash. */
.dancelooper-app #dancelooper_header .dancelooper-logomark,
.dancelooper-app #dancelooper_header .dancelooper-wordmark,
.dancelooper-app #dancelooper_header .dancelooper-brand
{
    cursor: pointer;
}
