:root {
    --font-main: Poppins, sans-serif;
    --font-title: Poppins, sans-serif;
    --transition-main: all 0.3s ease;
    --app-safe-top: env(safe-area-inset-top, 0px);
    --app-safe-bottom: env(safe-area-inset-bottom, 0px);
    /* Nonzero in landscape on a notched phone, where a bar docked across the
       screen has controls at both edges. */
    --app-safe-left: env(safe-area-inset-left, 0px);
    --app-safe-right: env(safe-area-inset-right, 0px);
    /* The resting space under the LOWEST pill of any bottom-docked bar. One
       value for the whole app — the editor's chip row, the photo tools dock and
       the projects pager all compose it the same way:

           padding-bottom: max(var(--app-bottom-foot), var(--app-safe-bottom))

       `max`, not `+`: the handoff draws its own home-indicator strip (a 134x5
       pill in a 26px band at the foot of its 874px canvas) and puts the photo
       bar's 20px padding INSIDE that band, so 20px IS the indicator allowance
       rather than something to add to it. Adding them double-counted and left
       a 54pt gap under a 36pt pill. On a device that reserves the indicator the
       inset wins; on one that does not, the 20px keeps the pills off the edge.
       The three bars previously used 25px (spare height in the sheet's detent,
       never a chosen number), 20px and 8px. */
    --app-bottom-foot: 20px;
    --app-header-base-height: 64px;
    --app-header-height: calc(var(--app-header-base-height) + var(--app-safe-top));
    --app-viewport-height: 100vh;
    --app-main-height: calc(var(--app-viewport-height) - var(--app-header-height));
}

@media (prefers-reduced-motion: no-preference) {
    @view-transition {
        navigation: auto;
    }
}

@supports (height: 100dvh) {
    :root {
        --app-viewport-height: 100dvh;
        --app-main-height: calc(var(--app-viewport-height) - var(--app-header-height));
    }
}

.project-image-load-failed {
    position: relative;
    background: var(--color-bg-alt);
}

.project-image-load-failed img[hidden] {
    display: none !important;
}

.project-image-load-fallback {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    box-sizing: border-box;
    padding: 12px;
    border: 1px solid var(--color-border);
    background: var(--color-bg-alt);
    color: var(--color-text-muted);
    text-align: center;
    pointer-events: none;
}

.project-image-load-fallback__icon {
    font-size: 30px;
    line-height: 1;
}

.project-image-load-fallback__label {
    max-width: 22ch;
    font-size: 0.75rem;
    line-height: 1.3;
}

.analyzing-thumb .project-image-load-fallback {
    padding: 6px;
}

.analyzing-thumb .project-image-load-fallback__label {
    display: none;
}

:is(
    .people-thumb-img-wrap,
    .face-group-thumb-wrapper,
    .face-group-stacked-thumb-wrap,
    .face-group-photo-crop,
    .photo-person-avatar-wrap
) .project-image-load-fallback {
    border-radius: inherit;
    padding: 4px;
}

:is(
    .people-thumb-img-wrap,
    .face-group-thumb-wrapper,
    .face-group-stacked-thumb-wrap,
    .face-group-photo-crop,
    .photo-person-avatar-wrap
) .project-image-load-fallback__icon {
    font-size: 22px;
}

:is(
    .people-thumb-img-wrap,
    .face-group-thumb-wrapper,
    .face-group-stacked-thumb-wrap,
    .face-group-photo-crop,
    .photo-person-avatar-wrap
) .project-image-load-fallback__label {
    display: none;
}

body {
    font-family: var(--font-main);
    font-optical-sizing: auto;
    font-style: normal;
    line-height: 1.6;
    color: var(--color-text);
    background-color: var(--color-bg);
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    min-height: var(--app-viewport-height);
}

:where(a, button, input, textarea, select, summary, [role="button"], [tabindex]:not([tabindex="-1"])):focus-visible {    
    outline: 2px solid var(--color-focus-ring);
    outline-offset: 2px;
}

:where(body, body *) {
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
}

:where(input, textarea, select, [contenteditable], .allow-text-selection, .allow-text-selection *) {
    -webkit-user-select: text;
    -moz-user-select: text;
    -ms-user-select: text;
    user-select: text;
    -webkit-touch-callout: default;
}

.container {
    max-width: 1200px;
    width: 90%;
    margin: 0 auto;
    padding: 20px;
}

body.rearrange-hide-chat .main-content {
    padding: 0;
    width: 100%;
    min-height: var(--app-main-height);
}

body.rearrange-hide-chat .main-content .container {
    max-width: none;
    width: 100%;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    min-height: 0;
}

.main-content {
    padding: 40px 0;
    flex-grow: 1;
    margin-top: var(--app-header-height);
}

.site-side-rail-page .main-content .container {
    padding: 0;
    max-width: initial;
    width: 100%;
    margin: 0;
}

.page-description {
    max-width: 800px;
    margin: 0 auto 40px;
    text-align: center;
    color: var(--color-text-muted);
    font-size: 18px;
    line-height: 1.6;
}

.app-header {
    color: var(--color-text);
    /* The top border caps the honeycomb texture so its hard stop against
       whatever sits above (browser chrome, the status strip on phones)
       reads as a deliberate panel edge rather than a truncated pattern. */
    border-top: 1px solid var(--color-border);
    border-bottom: 1px solid var(--color-border);
    box-sizing: border-box;
    position: fixed;
    top: 0;
    left: 0;
    height: var(--app-header-height);
    width: 100%;
    /* Flat header surface behind the honeycomb texture. Light mode:
       --color-header-bg aliases --color-side-rail-bg, so the header and the
       side rail read as one continuous chrome. */
    background-color: var(--color-header-bg, var(--color-surface));
    /* Top-edge treatment (uniform on every platform): the border-top
       above caps the pattern; dark mode adds a black inner shadow, and
       light mode has a dormant gradient band via ::after. See the rules
       after this block. */
    z-index: 999;
    display: flex;
    padding-top: var(--app-safe-top);
}

/* Light mode's top edge: a gradient band (a linear fade, not a blur)
   from the header gray to transparent, painted above the honeycomb
   texture so the pattern fades into the flat header color at the top
   edge. Sits above the negative-z texture; content never occupies these
   top pixels.
   Disabled by the `transparent 100%` mix. The retained rule allows a visual
   trial by lowering that mix toward 0%; remove the block if this treatment
   is permanently excluded from the header design. */
.app-header::after {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 20px;
    background: linear-gradient(to bottom,
        color-mix(in srgb,
            var(--color-header-bg, var(--color-surface)), transparent 100%),
        transparent);
    pointer-events: none;
}

/* Dark mode keeps a black inner shadow instead of the gradient band. */
html.theme-dark .app-header {
    box-shadow: inset 0 9px 8px -6px rgba(var(--shadow-color-rgb) / 0.45);
}

html.theme-dark .app-header::after {
    display: none;
}

/* Honeycomb texture behind the header content (site_base.html). The header is
   a fixed-position stacking context, so z-index: -1 paints the texture above
   the header's own surface color but below all header content. */
.app-header-texture {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    z-index: -1;
    pointer-events: none;
    /* Logo guard (brand-guideline requirement for white-label marks):
       the texture is masked out across the header's left end so the
       logo always sits on the flat, opaque --color-header-bg, then
       fades in toward the right. Masking the texture is visually
       identical to an opaque header-color gradient layered between the
       pattern and the logo, but tracks any brand's header color for
       free. The fade begins right at the left edge (solid stop kept as
       a tuning knob at 0) and reaches full pattern at
       --header-logo-guard-end (LTR only: the app ships no RTL
       locales). */
    --header-logo-guard-solid: 0px;
    --header-logo-guard-end: 420px;
    -webkit-mask-image: linear-gradient(to right,
        transparent var(--header-logo-guard-solid),
        #000 var(--header-logo-guard-end));
    mask-image: linear-gradient(to right,
        transparent var(--header-logo-guard-solid),
        #000 var(--header-logo-guard-end));
}

/* Phone widths: the fade completes sooner so some pattern still shows
   before the right-side controls. */
@media (max-width: 480px) {
    .app-header-texture {
        --header-logo-guard-end: 256px;
    }
}

/* Touch devices drop the honeycomb pattern for a flat brand header. This
   covers every mobile user: phones and tablets, iOS and iPadOS (mobile
   Safari and the native Capacitor WKWebView shell all report `hover: none`),
   while desktop pointers (macOS/Windows/Linux, including the macOS app) keep
   the pattern. With no pattern to cap, the top border rule is dropped too so
   the header meets the status strip / browser chrome with no visible line. */
@media (hover: none) {
    .app-header {
        border-top: none;
    }

    /* Flatten the dark-mode top edge too: drop the inner top shadow so the
       mobile header has no top rule, pattern, or glow on any platform. Same
       selector as the shadow rule above so it wins the cascade on match. */
    html.theme-dark .app-header {
        box-shadow: none;
    }

    .app-header-texture {
        display: none;
    }
}

.app-header-texture__major,
.app-header-texture__minor {
    fill: none;
    stroke-width: 1.5;
}

.app-header-texture__major {
    stroke: var(--color-header-texture-major);
}

.app-header-texture__minor {
    stroke: var(--color-header-texture-minor);
}

.app-header .container {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px;
    margin: 0;
    width: 100%;
    max-width: none;
}

.header-left {
    display: flex;
    align-items: center;
}

.header-right {
    display: flex;
    align-items: center;
    gap: 12px;
}

.header-center {
    flex: 1 1 auto;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 32px;
    text-align: center;
}

.header-center:empty {
    display: none;
}

.header-actions {
    display: flex;
    align-items: center;
    gap: 12px;
}

.header-actions:empty {
    display: none;
}

.header-utilities {
    display: flex;
    align-items: center;
    gap: 12px;
}

.header-utilities:empty {
    display: none;
}

.header-ai-label {
    display: none;
    /* 8px beyond the header-actions gap keeps the descriptor separate
       from the language selector cluster. */
    margin: 0 0 0 8px;
    color: var(--color-text);
    font-family: "Poppins", var(--font-main);
    font-size: 18px;
    font-weight: 400;
    line-height: 1.2;
}

@media (min-width: 1048px) {
    .header-ai-label {
        display: inline-flex;
        align-items: center;
    }

    .site-side-rail-page .app-header .header-utilities {
        display: none;
    }
}

.logo {
    display: flex;
    align-items: center;
}

.logo img {
    height: 28px;
}

.logo-img {
    height: 28px;
    width: auto;
}

/* Phone widths: one shared logo size on every page, constrained by
   HEIGHT so every brand logotype keeps its own aspect ratio (the Mimeo
   white-label mark is ~6:1 vs Motif's ~2.9:1 — a fixed width would
   render it half as tall). 26px puts Motif at ~76px wide, splitting the
   difference between the old natural ~82px (projects et al.) and the
   editor's former 72px compaction (editor-chrome.css), which squashed
   the aspect against the base 28px height. Outranks
   `.logo img { height: 28px }` on class count. */
@media (max-width: 480px) {
    .logo .logo-img {
        height: 26px;
        width: auto;
        /* No width cap here: uncrowded routes (projects, landing) have
           room for wide white-label marks (Mimeo ~6:1 renders ~155px at
           this height, in line with its pre-existing mobile size). The
           crowded EDITOR header caps the box instead — see the ≤480px
           logo rule in editor-chrome.css. */
    }
}

.logo-img--dark {
    display: none;
}

html.theme-dark .logo-img--light {
    display: none;
}

html.theme-dark .logo-img--dark {
    display: block;
}

.btn.btn--header-checkout {
    background: #43A047;
    border-radius: 38px;
    color: #fff;
    padding: 6px 16px;
    font-size: 16px;
    font-weight: 500;
    display: flex;
    align-items: center;
    gap: 6px;
    border: none;
    cursor: pointer;
    /* No extra margin: header button spacing is owned solely by the
       .header-actions flex gap so Preview/Share/Buy space evenly. */
}

.btn.btn--header-checkout .spinner {
    height: 14px;
    width: 14px;
    margin-right: 0;
}

.btn.btn--header-checkout:hover {
    background: var(--color-success);
    transform: none;
}

.icon {
    font-family: 'Material Symbols Rounded';
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    line-height: 1;
    letter-spacing: normal;
    text-transform: none;
    vertical-align: middle;
    user-select: none;
    color: currentColor;
}

.icon--spin {
    animation: spin 1s linear infinite;
    transform-origin: 50% 50%;
}

.help-button {
    width: 32px;
    height: 32px;
    border-radius: 32px;
    border: 1px solid var(--color-border);
    display: flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
    background: var(--color-surface);
    color: var(--color-text);
    font-weight: 600;
    font-size: 14px;
    cursor: pointer;
    transition: background 0.2s ease, color 0.2s ease;
}

html.theme-dark .help-button {
    border-color: #d9d9d9;
}

html.theme-dark .help-button:disabled {
    border-color: #d9d9d9;
}

.help-button:hover {
    background: var(--color-surface-alt);
    color: var(--color-text);
}

.cta-button--bright-gradient {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    text-align: center;
    text-decoration: none;
    color: #fff;
    font-family: "Roboto", sans-serif;
    font-size: 16px;
    font-weight: 700;
    line-height: 1;
    border: none;
    border-radius: 24px;
    background: var(--gradient-bright-blue);
}

.help-button:disabled {
    opacity: 0.4;
    cursor: not-allowed;
    color: var(--color-button-disabled-text);
    background: var(--color-bg-alt);
    border-color: var(--color-button-disabled-border);
}

.help-button__icon {
    line-height: 1;
}

.help-button .icon,
.help-button__icon .icon {
    font-size: 18px;
}

.avatar-widget {
    position: relative;
    display: flex
}

.avatar-trigger {
    width: 40px;
    height: 40px;
    border-radius: 40px;
    border: 1px solid var(--color-border-strong);
    background: var(--color-surface);
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    cursor: pointer;
}

/* Dark mode: match the light border the round `.help-button`s wear (they
   override to #d9d9d9 in dark). The avatar sits in the same rail/header row as
   those buttons, so its default `--color-border-strong` (#1A1A1A) read as a
   near-invisible dark ring against the dark surface while its neighbours had a
   crisp light one. */
html.theme-dark .avatar-trigger {
    border-color: #d9d9d9;
}

.avatar-trigger:focus {
    outline: 2px solid var(--color-focus-ring);
    outline-offset: 2px;
}

.avatar-trigger img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.coachmark {
    position: absolute;
    transform: translateY(-8px);
    width: 220px;
    padding: .75rem 1rem;
    border-radius: .5rem;
    background: var(--active-color);
    color: var(--color-text-inverse);
    box-shadow: var(--shadow-soft);
    font-size: .83rem;
    opacity: 0;
    transition: opacity .3s ease, transform .3s ease;
    pointer-events: none;
    box-sizing: border-box;
    left: -220px;
}

.coachmark::after {
    content: '';
    position: absolute;
    right: -4px;
    top: 6px;
    width: 12px;
    height: 12px;
    transform: rotate(45deg);
    background: inherit;
}

.coachmark.visible {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

.avatar-popover {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    width: 240px;
    background: var(--color-elevated);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    box-shadow: var(--shadow-hard);
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-4px);
    transition: opacity 0.2s ease, transform 0.2s ease;
    background-clip: padding-box;
    z-index: 1200;
}

.avatar-popover[aria-hidden="true"] {
    display: none;
}

.avatar-widget.is-open .avatar-popover {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

.avatar-widget[data-avatar-context="book"] .avatar-popover {
    top: 50%;
    left: calc(100% + 12px);
    right: auto;
    transform: translate(-8px, -50%);
}

.avatar-widget[data-avatar-context="book"].is-open .avatar-popover {
    transform: translate(0, -100%);
}

.avatar-popover__identity {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.avatar-popover__name {
    font-size: 14px;
    font-weight: 600;
    color: var(--color-text);
}

.avatar-popover__email {
    font-size: 14px;
    font-weight: 400;
    color: var(--color-text-muted);
    word-break: break-word;
}

.avatar-popover__separator {
    border: none;
    height: 1px;
    background: var(--color-border);
    margin: 0;
}

.avatar-popover__actions {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-left: -8px;
    margin-right: -8px;
}

.avatar-popover__theme-group {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.avatar-popover__submenu-wrap {
    position: relative;
    display: flex;
    flex-direction: column;
}

.avatar-popover__submenu-caret {
    margin-left: auto;
    font-size: 18px;
    color: var(--color-text-muted);
}

.avatar-popover__submenu {
    display: none;
    position: absolute;
    top: -0.375rem;
    right: 100%;
    min-width: 8rem;
    background: var(--color-elevated);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    box-shadow: var(--shadow-hard);
    padding: 6px;
    z-index: 1300;
}

.avatar-widget[data-avatar-context="book"] .avatar-popover__submenu {
    right: auto;
    left: 100%;
}

/* On narrow screens the side flyout can run off-screen; expand inline instead. */
@media (max-width: 600px) {
    .avatar-popover__submenu,
    .avatar-widget[data-avatar-context="book"] .avatar-popover__submenu {
        position: static;
        top: auto;
        right: auto;
        left: auto;
        min-width: 0;
        margin: 2px 0 2px 1.75rem;
        padding: 0;
        background: none;
        border: none;
        box-shadow: none;
    }
}

.avatar-popover__submenu-wrap:hover > .avatar-popover__submenu,
.avatar-popover__submenu-wrap.is-open > .avatar-popover__submenu {
    display: block;
}

.avatar-popover__btn {
    border: none;
    border-radius: 8px;
    padding: 8px;
    font-size: 14px;
    font-weight: 400;
    cursor: pointer;
    transition: background 0.2s ease, color 0.2s ease;
    font-family: Roboto;
    align-items: center;
    justify-content: flex-start;
    gap: 8px;
    background: none;
    color: var(--color-text);
    text-decoration: none;
    text-align: left;
}

.avatar-popover__btn:not([hidden]) {
    display: flex;
}

.avatar-popover__btn .icon {
    font-size: 18px;
}

.avatar-popover__btn:hover {
    background: var(--color-surface-alt);
}

.avatar-popover__btn--theme {
    justify-content: flex-start;
    align-items: center;
}

.avatar-popover__btn--theme[data-selected="true"] {
    background: var(--color-surface-alt);
    font-weight: 500;
}

.avatar-popover__btn--theme[data-selected="true"] .icon {
    color: var(--color-gradient-start);
}

.avatar-popover__btn-text {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    line-height: 1.2;
}

.card {
    background-color: var(--color-surface);
    border-radius: 8px;
    box-shadow: var(--shadow-soft);
    padding: 30px;
    margin-bottom: 30px;
    transition: var(--transition-main);
}

.card:hover {
    box-shadow: var(--shadow-hard);
}

#auth-prompt {
    margin-top: 40px;
}

#auth-prompt .card {
    text-align: center;
}

.btn {
    /* Compact pill — matches the `.btn-gradient` primary-action
       size (32px tall, 14px font, 18px horizontal padding) and the
       Delete Project dialog buttons. One control size across the
       app: dialogs, project cards, share controls, etc. */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 32px;
    padding: 0 18px;
    background-color: var(--color-accent);
    color: var(--color-text-on-gradient);
    border: 1px solid transparent;
    border-radius: 999px;
    /* `<button>` doesn't inherit font-family by default (UA hardcoded
       to Arial-ish). Force the app font so dialog buttons stay in
       Poppins like the surrounding title and body. */
    font-family: var(--font-main);
    font-size: 14px;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    transition: transform 0.2s ease, background-color 0.2s ease;
    text-align: center;
    text-decoration: none;
}

.btn:hover {
    background-color: var(--color-accent-hover);
}

.btn:disabled,
.btn[disabled] {
    background-color: var(--color-button-disabled-bg);
    border-color: var(--color-button-disabled-border);
    color: var(--color-button-disabled-text);
    cursor: not-allowed;
    opacity: 0.6;
    pointer-events: none;
}

.btn--large {
    padding: 15px 30px;
    font-size: 18px;
}

.btn--secondary {
    background-color: var(--secondary-color);
    color: var(--color-text-inverse);
}

.btn--secondary:hover {
    background-color: var(--color-text);
}

.btn--accent {
    background-color: var(--color-danger);
}

.btn--accent:hover {
    background-color: var(--color-danger-hover);
}

.btn--nav {
    border-radius: 50%;
    width: 40px;
    height: 40px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--secondary-color);
}

.btn--nav:hover {
    background-color: var(--color-text);
    transform: translateY(-2px);
}

.controls-group {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 15px;
    margin-bottom: 20px;
}

.controls-group--compact {
    margin-bottom: 0;
}

.modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: var(--color-overlay);
    display: none;
    justify-content: center;
    align-items: center;
    z-index: 1000;
    opacity: 0;
    visibility: hidden;
    transition: var(--transition-main);
}

.modal-overlay.active {
    opacity: 1;
    visibility: visible;
    display: flex;
}

.modal-content {
    background-color: var(--color-elevated);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    padding: 20px;
    /* Compact dialog by default — matches the Delete Project /
       Clone / Rename pattern. Width split into width + max-width so
       larger surfaces (Keyboard Shortcuts, Share modal, etc.) can
       widen via `max-width` overrides. */
    width: calc(100% - 32px);
    max-width: 420px;
    box-shadow: var(--shadow-soft);
    text-align: center;
    transform: translateY(-20px);
    transition: transform 0.3s ease;
}

.modal-overlay.active .modal-content {
    transform: translateY(0);
}

/* A dialog must never reach the screen edges. `width` and `max-width` above
   size the CONTENT box, so this dialog's 20px padding and 1px border are ADDED
   to them: `calc(100% - 32px)` rendered WIDER than the viewport on a phone
   (measured 398px inside 390px — 4px off each edge, radius cropped). Size the
   BORDER box instead once the viewport is too narrow for `max-width` to bind.
   494px is where the two models agree (420 content + 40 padding + 2 border =
   462, plus the 32px inset), so the box never jumps at the boundary and never
   grows wider than it is today. Applies to every `.modal-content`, including
   the surfaces that raise `max-width` — they overflowed further still.
   Tripwire: tests/test_dialog_viewport_fit_browser.py. */
@media (max-width: 494px) {
    .modal-content {
        box-sizing: border-box;
        max-width: calc(100% - 32px);
    }
}

.modal-header {
    margin: 0;
    padding: 0 0 12px 0;
    display: flex;
    justify-content: space-between;
    align-items: center;
    border-bottom: 1px solid var(--color-border);
}

.modal-header h2,
.modal-header h3 {
    margin: 0;
    font-size: 18px;
    font-weight: 500;
    color: var(--color-text);
}

.modal-header .close {
    width: 32px;
    height: 32px;
    cursor: pointer;
    border: none;
    background: none;
    color: var(--color-text-muted);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.modal-header .close .icon {
    font-size: 22px;
}

.modal-header .close:hover {
    opacity: 1;
    color: var(--color-text);
}

.modal-title {
    color: var(--secondary-color);
    margin-top: 0;
}

.modal-body {
    /* Compact body text size for modal copy. Larger / more
       structured modals (Keyboard Shortcuts, Share modal) restore
       their own sizes per-component. */
    font-size: 14px;
    color: var(--secondary-color);
    margin: 12px 0 0 0;
}

.modal-actions {
    display: flex;
    justify-content: center;
    gap: 10px;
    margin-top: 16px;
}

/* Pre-checkout content-quality review modal (built in static/js/site-checkout.js).
   Reuses the shared .modal-* chrome; each row pairs the issue's one-line
   descriptor (with a help-icon tooltip carrying the longer description) with a
   page link that jumps the canvas to the flagged surface. */
.checkout-quality-modal .modal-content {
    max-width: 520px;
    box-sizing: border-box;
    text-align: left;
}

/* "Apply a theme from another project" picker (Themes panel). Shared
   .modal-* chrome; each row is a button leading with a theme swatch tile,
   then the project title over the theme name. */
.theme-from-project-modal .modal-content {
    max-width: 520px;
    text-align: left;
}

.theme-from-project-intro {
    margin: 0 0 12px;
    font-size: 14px;
    color: var(--color-text-muted);
    line-height: 1.5;
}

.theme-from-project-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-height: min(52vh, 420px);
    overflow-y: auto;
}

.theme-from-project-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    border: 1px solid var(--color-border);
    border-radius: 10px;
    background: var(--color-surface);
    cursor: pointer;
    text-align: left;
}

.theme-from-project-row:hover {
    border-color: var(--color-accent);
}

.theme-from-project-preview {
    position: relative;
    flex: 0 0 64px;
    height: 44px;
    border: 1px solid var(--color-border);
    border-radius: 6px;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    overflow: hidden;
}

.theme-from-project-preview img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.theme-from-project-more {
    display: block;
    width: 100%;
    padding: 10px 12px;
    border: 1px dashed var(--color-border);
    border-radius: 10px;
    background: none;
    font-size: 13px;
    color: var(--color-accent-fg);
    cursor: pointer;
    text-align: center;
}

.theme-from-project-more:hover {
    border-color: var(--color-accent);
}

.theme-from-project-more:disabled {
    opacity: 0.6;
    cursor: default;
}

.theme-from-project-dots {
    display: flex;
    gap: 3px;
    padding-bottom: 6px;
}

.theme-from-project-dots i {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    border: 1px solid rgba(0, 0, 0, 0.12);
}

.theme-from-project-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.theme-from-project-title {
    font-weight: 600;
    color: var(--color-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.theme-from-project-meta {
    font-size: 13px;
    color: var(--color-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.theme-from-project-empty {
    margin: 8px 0;
    font-size: 14px;
    color: var(--color-text-muted);
    line-height: 1.5;
}

.checkout-quality-modal__header {
    align-items: flex-start;
}

.checkout-quality-modal__heading {
    text-align: left;
}

.checkout-quality-modal__title {
    margin: 0;
}

.checkout-quality-modal__summary {
    margin: 4px 0 0 0;
    font-size: 14px;
    color: var(--color-text);
    line-height: 1.4;
}

/* No extra top margin: the gap between the header divider and the first row
   must equal the row padding, so the divider rhythm is uniform. */
.checkout-quality-modal .modal-body {
    max-height: min(52vh, 420px);
    overflow-y: auto;
    margin-top: 0;
}

.checkout-quality-modal__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
}

/* One row per (issue, page): issue text left, page link right, separated by
   hairline dividers like the rest of the app's list chrome. Every row keeps
   its bottom divider — including the last — so the list reads as a closed
   table between the header divider and the footer. */
.checkout-quality-modal__item {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--color-border);
}

.checkout-quality-modal__text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 8px;
}

.checkout-quality-modal__item-title {
    font-size: 15px;
    font-weight: 400;
    color: var(--color-text);
    line-height: 1.35;
}

/* Help icon (leads the row, before the descriptor): hyperlink-colored; the
   canonical longer description shows in the shared instant tooltip below
   (no native title attribute, so there is no OS hover delay). Standard
   cursor — never the question-mark help cursor. */
.checkout-quality-modal__help {
    display: inline-flex;
    align-items: center;
    color: var(--color-accent-fg);
    cursor: default;
}

.checkout-quality-modal__help .material-symbols-rounded {
    font-size: 18px;
}

.checkout-quality-modal__help:focus-visible {
    outline: 2px solid var(--color-focus-ring);
    outline-offset: 2px;
    border-radius: 50%;
}

/* Shared instant tooltip bubble (site-instant-tooltip.js): one
   fixed-position singleton shown the moment a `[data-instant-tooltip]`
   element is hovered or focused — no OS title delay, and no clipping by
   scrollable ancestors. Sits above every floating editor chrome layer
   (text toolbar 10000, Coloris 11000). */
.instant-tooltip {
    position: fixed;
    z-index: 12000;
    max-width: 280px;
    padding: 8px 12px;
    border-radius: 8px;
    background: var(--color-text);
    color: var(--color-text-inverse);
    font-family: var(--font-main);
    font-size: 12px;
    font-weight: 400;
    line-height: 1.45;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
    pointer-events: none;
}

.instant-tooltip[hidden] {
    display: none;
}

/* Page link, aligned with the issue title. Jumps the canvas to the flagged
   surface and closes the modal. */
.checkout-quality-modal__page-link {
    flex: 0 0 auto;
    margin-top: 1px;
    padding: 0;
    border: none;
    background: transparent;
    color: var(--color-accent-fg);
    font-family: var(--font-main);
    font-size: 14px;
    font-weight: 400;
    line-height: 1.5;
    white-space: nowrap;
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 2px;
}

.checkout-quality-modal__page-link:hover {
    color: var(--color-accent-fg-hover);
}

.checkout-quality-modal__page-link:focus-visible {
    outline: 2px solid var(--color-focus-ring);
    outline-offset: 2px;
    border-radius: 2px;
}

.checkout-quality-modal__hint {
    margin: 10px 0 0 0;
    font-size: 14px;
    color: var(--color-text);
    line-height: 1.4;
}

/* Footer: "I'll Fix These" is the default action and wears the shared
   `.btn-gradient` fill; "Ignore and Order" is the outlined secondary that
   proceeds despite the warnings. */
.checkout-quality-modal__actions {
    justify-content: flex-end;
    align-items: center;
}

/* The button is opened with programmatic focus; the shared focus outline
   renders as a squarish ring around the pill, so use a radius-following
   box-shadow ring instead (still clearly visible for keyboard users). */
.checkout-quality-modal__fix-these {
    color: var(--color-text-on-gradient, #FFFFFF);
}

.checkout-quality-modal__fix-these:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 40%, transparent);
}

.checkout-quality-modal__ignore {
    background: transparent;
    border: 1px solid var(--color-border);
    color: var(--color-text);
    font-weight: 400;
}

.checkout-quality-modal__ignore:hover {
    background: transparent;
    border-color: var(--color-accent);
    /* Label colour stays put on hover (the border is the hover affordance);
       an alternate button's text must not shift colour on hover/submit. */
}

/* Dark theme's near-black --color-border vanishes against the dialog
   surface; brighten to the same outline the shared pill controls use. */
html.theme-dark .checkout-quality-modal__ignore {
    border-color: #d9d9d9;
}

html.theme-dark .checkout-quality-modal__ignore:hover {
    border-color: var(--color-accent);
}

@media (max-width: 420px) {
    .checkout-quality-modal__actions {
        flex-direction: column;
        align-items: stretch;
    }

    .checkout-quality-modal__actions > * {
        width: 100%;
        height: auto;
        min-height: 32px;
        white-space: normal;
    }

    .checkout-quality-modal__fix-these {
        order: -1;
    }
}

@media (max-width: 1047px) {
    /* The intermediate assistant sheet covers roughly 64% of the canvas.
       Once a quality-issue link has been used, retain trailing scroll room
       whenever that sheet is open so the last surface stays visible after
       the smooth scroll settles. Closing the sheet removes the padding via
       this state-qualified selector without a parallel JS state machine. */
    body.checkout-quality-navigation-active:has(.chat-panel[data-sheet-state="intermediate"]) :is(#edit-book, #calendar-editor-root, #card-editor-root) {
        padding-bottom: 66vh;
    }
}

/* Shared project share-link modal. Included by book and calendar editors. */
#share-modal {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    display: none;
    align-items: center;
    justify-content: center;
    z-index: 1300;
    padding: 16px;
    box-sizing: border-box;
}

#share-modal.active {
    display: flex;
}

#share-modal .modal-content {
    background-color: var(--color-elevated);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    box-shadow: var(--shadow-soft);
    padding: 18px;
    width: min(630px, calc(100% - 32px));
    max-height: calc(var(--app-viewport-height) - 32px);
    overflow-y: auto;
    transform: translateY(-16px);
}

#share-modal.active .modal-content {
    transform: translateY(0);
}

#share-modal .modal-header {
    margin: 0;
    padding: 0 0 10px 0;
    border-bottom: 1px solid var(--color-border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

#share-modal .modal-title {
    font-weight: 600;
    font-size: 18px;
    color: var(--color-text);
    margin: 0;
}

#share-modal .modal-header .close {
    background: none;
    border: none;
    color: var(--color-text);
    padding: 4px;
    border-radius: 8px;
    cursor: pointer;
}

#share-modal .modal-header .close:hover {
    background: rgba(var(--shadow-color-rgb) / 0.08);
}

#share-modal .modal-body {
    font-size: 14px;
    color: var(--secondary-color);
    padding: 10px 0 6px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

#share-modal .modal-body p {
    margin: 0;
}

#share-modal .share-lede {
    padding-top: 4px;
}

#share-modal .share-url-container {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 12px;
    align-items: center;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 10px;
    padding: 5px 9px;
}

#share-modal input#share-url {
    width: 100%;
    border: none;
    background: transparent;
    color: var(--color-text);
    font-size: 15px;
    outline: none;
    padding-right: 16px;
    min-height: 28px;
}

#share-modal .share-copy-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 14px;
    height: 36px;
    border-radius: 8px;
    background: var(--gradient-bright-blue);
    border: none;
    color: var(--color-text-on-gradient);
    font-weight: 600;
    cursor: pointer;
}

#share-modal .share-copy-btn .icon {
    font-size: 20px;
}

#share-modal .share-copy-btn:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(50, 130, 255, 0.25);
}

#share-modal .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 18px;
    height: 34px;
    border-radius: 999px;
    font-size: 14px;
    line-height: 1;
    min-width: 0;
    border: 1px solid transparent;
    cursor: pointer;
    transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
}

#share-modal .btn-cancel {
    background-color: var(--color-surface);
    border-color: var(--color-border);
    color: var(--color-text);
}

#share-modal .btn-cancel:hover {
    background-color: rgba(var(--shadow-color-rgb) / 0.08);
}

#share-modal .btn-primary {
    background: var(--gradient-bright-blue);
    border: none;
    color: var(--color-text-on-gradient);
    font-weight: 600;
}

#share-modal .btn-primary:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(50, 130, 255, 0.25);
}

.keyboard-shortcuts-modal .modal-content {
    max-width: 760px;
    text-align: left;
    padding-bottom: 24px;
    max-height: 90vh;
    display: flex;
    flex-direction: column;
    margin: 0 20px;
}

.keyboard-shortcuts__sections {
    display: flex;
    flex-direction: column;
    gap: 18px;
    width: 100%;
}

.keyboard-shortcuts__section {
    break-inside: auto;
    page-break-inside: auto;
    margin: 0;
}

.keyboard-shortcuts__section-title {
    font-size: 14px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    margin: 0 0 8px;
}

.keyboard-shortcuts__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    column-gap: 24px;
    row-gap: 12px;
}

.keyboard-shortcuts__intro {
    margin-top: 0;
}

.keyboard-shortcuts__row {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    justify-content: space-between;
    break-inside: avoid;
    page-break-inside: avoid;
    -webkit-column-break-inside: avoid;
    -moz-column-break-inside: avoid;
    column-break-inside: avoid;
}

.keyboard-shortcuts__desc {
    flex: 1 1 50%;
    color: var(--color-text);
    font-weight: 300;
    font-size: 14px;
}

.keyboard-shortcuts__keys {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    justify-content: flex-end;
}

.keyboard-shortcuts__combo {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.keyboard-shortcuts__plus,
.keyboard-shortcuts__or {
    color: var(--color-text-muted);
    font-size: 12px;
}

.keyboard-shortcuts__or {
    font-weight: 600;
}

.keyboard-shortcuts__empty {
    margin: 0;
    color: var(--color-text-muted);
}

.keyboard-shortcuts-modal .modal-body {
    overflow-y: auto;
    padding-right: 8px;
}

kbd {
    display: inline-block;
    padding: 4px 7px;
    border-radius: 6px;
    border: 1px solid var(--color-border);
    background: var(--color-surface-alt);
    box-shadow: inset 0 -1px 0 rgba(var(--shadow-color-rgb) / 0.12);
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
    font-size: 12px;
    line-height: 1.2;
    color: var(--color-text);
}

/* --- What's New modal --- */
.whats-new-modal {
    overscroll-behavior: contain;
    overflow: hidden;
}

.whats-new-modal .modal-content {
    max-width: 560px;
    text-align: left;
    padding: 0;
    border: none;
    border-radius: 8px;
    /* Cap at 70% of the viewport on every breakpoint. The trailing
       margin-bottom nudges the dialog just above vertical center: the
       overlay centers the flex item's margin-box, so a bottom margin
       shifts the visible dialog up by half its value, independent of
       the dialog's actual content height. */
    max-height: calc(100vh * 0.7);
    max-height: calc(var(--app-viewport-height) * 0.7);
    display: flex;
    flex-direction: column;
    margin: 0 20px 6vh;
    overscroll-behavior: contain;
    box-sizing: border-box;
    overflow: hidden;
}

.whats-new-modal .modal-header {
    background: var(--gradient-bright-blue);
    min-height: 56px;
    padding: 0 12px 0 20px;
    border-bottom: 1px solid var(--color-border);
    border-radius: 8px 8px 0 0;
    margin: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.whats-new-modal .modal-header h3 {
    font-weight: 500;
    line-height: 1.2;
    color: #fff;
}

.whats-new-modal .modal-header .close {
    color: rgba(255, 255, 255, 0.7);
    line-height: 1;
}

.whats-new-modal .modal-header .close:hover {
    color: #fff;
}

.whats-new-modal .modal-body {
    flex: 1 1 auto;
    min-height: 0;
    margin: 0;
    overflow-y: auto;
    padding: 24px 48px;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    touch-action: pan-y;
}

.whats-new-modal .modal-body h3 {
    font-size: 15px;
    font-weight: 500;
    letter-spacing: 0.03em;
    color: var(--color-text);
    margin: 20px 0 8px;
}

.whats-new-modal .modal-body h3:first-of-type {
    margin-top: 0;
}

/* site-whats-new.js wraps only a complete leading emoji grapheme, leaving
   plain and legacy headings at the normal heading size. */
.whats-new-modal .modal-body h3 .whats-new__emoji {
    font-size: calc(1em + 4px);
    line-height: 1;
    margin-right: 0.25em;
}

.whats-new-modal .modal-body p {
    font-size: 15px;
}

/* The intro summary sits a step larger than the section body to anchor the
   modal, but shares the list items' 1.5 line-height so it does not read
   loose. Scoped to the first top-level paragraph so section/pointer text
   (and, in older notes, the top-level pointer paragraphs) stay at 15px. */
.whats-new-modal .modal-body > p:first-of-type {
    font-size: 16px;
    line-height: 1.5;
    margin-top: 12px;
    margin-bottom: 20px;
}

.whats-new-modal .modal-body ul {
    list-style: none;
    /* Indent the bullet column to the heading text, which starts after the
       emoji glyph (a uniform ~19px advance in the app's emoji font), its
       0.25em trailing margin, and the following space. A fixed value can
       drift on platforms whose emoji font uses variable advances. */
    margin: 0 0 0 28px;
    padding: 0;
}

.whats-new-modal .modal-body li {
    position: relative;
    padding-left: 16px;
    margin-bottom: 8px;
    font-size: 15px;
    font-weight: 300;
    line-height: 1.5;
    color: var(--color-text);
}

.whats-new-modal .modal-body li::before {
    content: '•';
    position: absolute;
    left: 0;
    color: var(--color-text-muted);
}

/* A marquee section is one bullet: the benefit sentence, then its
   "Where to Find It:" pointer on its own line inside the same list item.
   The tag set has no <br>, so a nested paragraph carries the real line
   break and the section body's 15px vertical rhythm without a second
   bullet (only li::before draws one). */
.whats-new-modal .modal-body li p {
    margin: 15px 0 0;
}

.whats-new-modal .modal-actions {
    margin: 0;
    padding: 10px 20px;
    background: var(--color-bg-alt);
    border-top: 1px solid var(--color-border);
    border-radius: 0 0 8px 8px;
}

.whats-new-modal .modal-actions .cta-button--bright-gradient {
    padding: 6px 24px;
    font-size: 13px;
    cursor: pointer;
}

@media (max-width: 600px) {
    .whats-new-modal .modal-content {
        margin: 0 16px 6vh;
    }

    .whats-new-modal .modal-body {
        padding: 24px 28px;
    }
}

.whats-new__loading,
.whats-new__error {
    color: var(--color-text-muted);
    font-size: 15px;
    font-weight: 300;
}

/* Lock page scroll behind the What's New modal (wheel/trackpad). The class
   is set on both html and body so the lock hits the scrolling element
   directly regardless of which one it is. Touch scroll is held by a
   touchmove guard in site-whats-new.js. */
html.whats-new-open,
body.whats-new-open {
    overflow: hidden;
}

.btn-cancel {
    /* Surface-fill ghost — slightly distinct from the elevated
       dialog surface so the button reads as a clickable target. */
    background-color: var(--color-surface);
    border: 1px solid var(--color-border);
    color: var(--color-text);
    box-shadow: none;
}

.btn-cancel:hover {
    background-color: rgba(var(--shadow-color-rgb) / 0.08);
}

/* The shared JS-built dialog (site-modal-dialog.js) opens over live
   editing surfaces, whose floating chrome deliberately outranks the
   generic modal overlay (text toolbar 10000, Coloris picker 11000).
   A modal dialog must sit above all of it. */
.modal-overlay.site-dialog {
    z-index: 11500;
}

/* Canonical dialog position: the dialog hangs above the viewport's
   vertical center (its BOTTOM edge sits just above center) instead of
   being centered — centered reads as "too low" for short dialogs. */
.site-dialog .modal-content {
    position: absolute;
    bottom: calc(50% + 16px);
}

/* Dialog messages are plain text; multi-paragraph content (e.g. the
   support-ticket draft review) arrives with newlines. Long drafts
   scroll inside the message instead of pushing the actions off screen. */
.site-dialog .modal-body p {
    white-space: pre-line;
    max-height: 40vh;
    overflow-y: auto;
}

/* Three label-sized actions can exceed the compact dialog width on
   phone screens (longer localized labels especially) — wrap instead
   of spilling. */
.site-dialog .modal-actions {
    flex-wrap: wrap;
}

/* Run the header divider edge to edge across the 20px content padding. */
.site-dialog .modal-content:has(.spacing-dialog) .modal-header {
    margin-inline: -20px;
    padding-inline: 20px;
}

/* Support-ticket editor inside the shared dialog: labeled, left-aligned
   fields prefilled from the agent's draft. The bottom margin holds the
   action row clear of the editable body. The dialog box (not the form)
   owns the width, so the fields stay inside the dialog's padding. */
.site-dialog .modal-content:has(.support-ticket-form) {
    max-width: min(540px, calc(100vw - 32px));
    /* This dialog is much taller than the compact confirms the shared
       hang-above-center position was tuned for — center it on the
       viewport's vertical center instead. `translate` (not `transform`)
       so the entrance animation's transform still plays. */
    bottom: auto;
    top: 50%;
    translate: 0 -50%;
    /* Short viewports (phone landscape, on-screen keyboard): cap the
       dialog to the visible viewport and let the body scroll so the
       header and Send action stay reachable. border-box so the cap
       includes the dialog's own padding. */
    box-sizing: border-box;
    max-height: calc(100vh - 24px);
    max-height: calc(100dvh - 24px);
    display: flex;
    flex-direction: column;
}

.site-dialog .modal-content:has(.support-ticket-form) .modal-body {
    overflow-y: auto;
    min-height: 0;
    /* overflow-y:auto makes overflow-x compute to auto as well, which would
       clip each field's focus outline (2px width + 2px offset = 4px reach)
       at its left and right edges. Pad the scrollport by 6px — the ring's
       reach plus slack so fractional-pixel rendering (Retina, zoom) can't
       shave its outer edge — and pull the block/inline start back by the
       same amount so the fields and the header gap stay where they were. */
    padding: 6px;
    margin: 6px -6px 0;
}

.support-ticket-form {
    display: flex;
    flex-direction: column;
    gap: 14px;
    text-align: left;
    margin-bottom: 24px;
}

.support-ticket-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.support-ticket-field label {
    font-size: 13px;
    color: var(--secondary-color);
    text-align: left;
}

.support-ticket-field input,
.support-ticket-field textarea {
    padding: 9px 12px;
    border-radius: 10px;
    border: 1px solid var(--color-border);
    background-color: var(--color-surface);
    color: var(--color-text);
    font-size: 14px;
    font-family: inherit;
    width: 100%;
    box-sizing: border-box;
}

.support-ticket-field textarea {
    resize: vertical;
    min-height: 150px;
    max-height: 40vh;
}

.support-ticket-field input:focus-visible,
.support-ticket-field textarea:focus-visible {
    outline: 2px solid var(--color-focus-ring);
    outline-offset: 2px;
}

/* Canonical dialog buttons: width hugs the label, with a slightly
   wider horizontal inset than the vertical one so the pill doesn't
   crowd its label. Alternate actions use regular weight; the default
   action is medium. */
.site-dialog .modal-actions .btn {
    height: auto;
    padding: 9px 14px;
    font-weight: 400;
}

.site-dialog .modal-actions .btn-primary,
.site-dialog .modal-actions .btn-delete {
    font-weight: 500;
}

/* Non-destructive primary action in the shared JS-built dialog
   (site-modal-dialog.js) — the same blue gradient the Clone / Rename
   Project modals scope to themselves in page-projects.css, with
   medium-weight white type. */
.site-dialog .btn-primary {
    background: var(--gradient-bright-blue);
    border: none;
    color: var(--color-text-on-gradient);
    font-weight: 500;
}

.site-dialog .btn-primary:hover {
    transform: translateY(-1px);
    background: var(--gradient-bright-blue);
}

.site-dialog .btn-primary:focus-visible {
    outline: 2px solid rgba(50, 130, 255, 0.45);
    outline-offset: 2px;
}

/* Destructive primary action (Delete, Remove, Shorten, etc.).
   Cherry-red gradient on the same 180deg slope as the blue
   `.btn-gradient` family. Pill shape inherited from `.btn`. The
   1px lift on hover is the only affordance — no drop shadow / glow. */
.btn-delete {
    background: var(--gradient-cherry-red);
    color: var(--color-text-on-gradient, #fff);
    border: none;
    font-weight: 600;
    transition: transform 0.2s ease, background-color 0.2s ease;
}

.btn-delete:hover:not(:disabled) {
    transform: translateY(-1px);
    background: var(--gradient-cherry-red);
}

.btn-delete:disabled,
.btn-delete[disabled] {
    /* Inherit the disabled-state palette from `.btn` so the cherry
       gradient doesn't bleed through when the action is unavailable. */
    background: var(--color-button-disabled-bg);
    color: var(--color-button-disabled-text);
}

/* For share URL functionality */
.share-url-container {
    display: flex;
    margin: 15px 0;
}

.share-url-container input {
    flex-grow: 1;
    padding: 10px;
    border: 1px solid var(--color-border);
    border-radius: 4px 0 0 4px;
    font-size: 14px;
}

.share-url-container .btn {
    background-color: var(--color-accent);
    color: var(--color-text-on-gradient);
    border: 1px solid transparent;
    border-radius: 0 4px 4px 0;
    padding: 10px 15px;
    cursor: pointer;
}

.share-url-container .btn:hover {
    background-color: var(--color-accent-hover);
}

.share-url-container .btn .icon {
    font-size: 20px;
}

.share-note {
    color: var(--color-text-muted);
    font-size: 14px;
    margin-bottom: 10px;
}

.share-expires {
    color: var(--color-text-muted);
    font-size: 13px;
    font-style: italic;
}

.loading-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: var(--color-overlay-inverse);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    z-index: 1000;
}

.loading-overlay .btn {
    background-color: var(--color-surface);
    color: var(--color-text);
}

.spinner {
    display: inline-block;
    border-radius: 50%;
    animation: spin 1s linear infinite;
    position: relative;
}

@keyframes spin {
    0% {
        transform: rotate(0deg);
    }

    100% {
        transform: rotate(360deg);
    }
}

.spinner--small {
    width: 1em;
    height: 1em;
    border: 0.15em solid currentColor;
    border-right-color: transparent;
}

.spinner--large {
    --spinner-border-width: 6px;
    width: 50px;
    height: 50px;
    border-radius: 50%;
    background: var(--gradient-bright-blue);
    -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - var(--spinner-border-width)), #000 calc(100% - var(--spinner-border-width) + 1px));
    mask: radial-gradient(farthest-side, transparent calc(100% - var(--spinner-border-width)), #000 calc(100% - var(--spinner-border-width) + 1px));
}

.spinner--large::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: conic-gradient(from 90deg, transparent 0deg 320deg, rgba(24, 28, 41, 0.4) 320deg 360deg);
    -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - var(--spinner-border-width)), #000 calc(100% - var(--spinner-border-width) + 1px));
    mask: radial-gradient(farthest-side, transparent calc(100% - var(--spinner-border-width)), #000 calc(100% - var(--spinner-border-width) + 1px));
    pointer-events: none;
}

.loading-spinner {
    margin-bottom: 20px;
}

.toast-container {
    position: fixed;
    top: calc(70px + var(--app-safe-top));
    right: 70px;
    z-index: 9999;
    max-width: 350px;
    width: 100%;
}

/* On narrow viewports the 70px desktop offset plus the 350px width would push
   the container's left edge off-screen and clip the toast. Pin it to both
   edges instead and let it fill the available width. */
@media (max-width: 480px) {
    .toast-container {
        top: calc(16px + var(--app-safe-top));
        right: 12px;
        left: 12px;
        max-width: none;
        width: auto;
    }
}

.toast {
    background-color: var(--color-elevated);
    box-shadow: var(--shadow-soft);
    border-radius: 8px;
    padding: 16px 20px;
    margin-bottom: 10px;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    /* Action toasts wrap their button row below the message. */
    flex-wrap: wrap;
    font-family: var(--font-main);
    font-size: 14px;
    animation: toast-in 0.3s ease-in-out forwards;
    overflow: hidden;
    position: relative;
    max-width: 100%;
    opacity: 0;
    transform: translateY(-20px);
    /* Bold 8px left accent bar plus a thin 2px top/right frame, all in the
       state color (set per state below). Bottom is left borderless for the
       progress bar. */
    border-style: solid;
    border-width: 2px 2px 0 8px;
    border-color: transparent;
}

.toast.error {
    border-color: var(--color-danger);
}

.toast.success {
    /* Match the Buy button's unhovered green (.btn--header-checkout). */
    border-color: #43A047;
}

.toast.info {
    /* Match the gradient blue used by the progress bar / primary button. */
    border-color: var(--color-gradient-start);
}

.toast.warning {
    border-color: var(--color-warning);
}

.toast-content {
    flex: 1;
    margin-right: 10px;
}

.toast-close {
    font-size: 16px;
    color: var(--color-text-muted);
    cursor: pointer;
    background: none;
    border: none;
    padding: 0;
    height: 20px;
    width: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.toast-close:hover {
    color: var(--color-text);
}

.toast-actions {
    flex-basis: 100%;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 12px;
}

/* Alternate (secondary) action button: matches the app's outlined-secondary
   convention — same pill geometry, border, and 14px regular type as other
   buttons. A lone action always renders in this style (see site-toast.js). */
.toast-action-btn {
    appearance: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 32px;
    padding: 0 18px;
    background: none;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    color: var(--color-text);
    font-family: var(--font-main);
    font-size: 14px;
    font-weight: 400;
    line-height: 1;
    cursor: pointer;
    white-space: nowrap;
}

.toast-action-btn:hover {
    background-color: var(--color-bg-alt);
}

/* Default (primary) action button: shares the canonical .btn-gradient look —
   gradient fill, bold white type. It renders last in the DOM (see
   site-toast.js) so it sits on the right with focus order intact. */
.toast-action-btn--primary {
    /* No border (matches the canonical .btn-gradient). The inherited 1px
       border from .toast-action-btn, even when transparent, smeared the
       gradient's edge colors into a 1px ring — a dark line at the bottom and
       misshapen rounded ends. box-sizing:border-box keeps the 32px height
       identical to the bordered alternate button, so they still align. */
    border: none;
    background: linear-gradient(
        180deg,
        var(--color-gradient-start) 0%,
        var(--color-gradient-end) 100%
    );
    color: var(--color-text-on-gradient, #fff);
    font-weight: 600;
    transition: transform 0.2s ease;
}

.toast-action-btn--primary:hover {
    transform: translateY(-1px);
}

/* Dark theme's near-black --color-border vanishes against the toast surface;
   brighten to the same outline the shared pill controls use. */
html.theme-dark .toast-action-btn:not(.toast-action-btn--primary) {
    border-color: #d9d9d9;
}

.toast-progress {
    position: absolute;
    bottom: 0;
    left: 0;
    height: 4px;
    background-color: rgba(var(--shadow-color-rgb) / 0.1);
    width: 100%;
}

.toast-progress-bar {
    height: 100%;
    width: 100%;
    /* Gradient runs dark (right) to light (left), matching the app gradient. */
    background: linear-gradient(
        to right,
        var(--color-gradient-start) 0%,
        var(--color-gradient-end) 100%
    );
    animation: toast-progress 10s linear forwards;
}

@keyframes toast-in {
    0% {
        opacity: 0;
        transform: translateY(-20px);
    }

    100% {
        opacity: 1;
        transform: translateY(0);
    }
}

@keyframes toast-out {
    0% {
        opacity: 1;
        transform: translateY(0);
    }

    100% {
        opacity: 0;
        transform: translateY(-20px);
    }
}

@keyframes toast-progress {
    0% {
        width: 100%;
    }

    100% {
        width: 0%;
    }
}

/* Checkout button inside book-update-scrim (Safari fallback) */
.book-update-scrim__checkout-btn {
    flex-shrink: 0;
    border: none;
    border-radius: 24px;
    background: var(--gradient-bright-blue, linear-gradient(180deg, #3282FF 0%, #1C54AB 100%));
    color: #fff;
    font-family: var(--font-main, 'Roboto', sans-serif);
    font-size: 12px;
    font-weight: 500;
    padding: 5px 16px;
    cursor: pointer;
    line-height: normal;
    min-height: 26px;
    margin-left: auto;
}

.book-update-scrim__checkout-btn:hover {
    filter: brightness(1.1);
}

@media (max-width: 600px) {
    .book-update-scrim__card:has(.book-update-scrim__checkout-btn) {
        display: grid;
        grid-template-columns: auto 1fr;
        gap: 10px;
    }

    .book-update-scrim__checkout-btn {
        grid-column: 1 / -1;
        justify-self: end;
        padding: 7px 20px;
        font-size: 13px;
        min-height: 30px;
    }
}

@media (max-width: 768px) {
    .app-header .container {
        flex-direction: row;
        text-align: left;
    }

    .main-nav {
        margin-top: 15px;
        width: 100%;
    }

    .keyboard-shortcuts__sections {
        column-count: 1;
    }

    .main-nav ul {
        justify-content: center;
    }

    .hide-on-mobile {
        display: none !important;
    }

    #user-section {
        gap: 0 !important;
    }

    .main-nav li {
        margin-left: 10px;
    }

    .main-nav a {
        padding: 8px 10px;
    }

    .btn.btn--header-checkout .text {
        display: none;
    }
}

@media (max-width: 1024px) {
    .help-widget[data-help-context="rail"] .help-popover {
        top: calc(100% + 8px);
        left: 0;
        right: auto;
        transform: translateY(-4px);
        max-width: calc(100vw - 24px);
    }

    .help-widget[data-help-context="rail"].is-open .help-popover {
        transform: translateY(0);
    }
}

/* Dim text while a new font is loading */
.font-loading {
    opacity: 0.5;
    transition: opacity 0.2s ease-in-out;
}

.main-nav a .icon {
    margin-right: 6px;
    font-size: 18px;
}

.btn .icon:not(:only-child) {
    margin-right: 8px;
}

/* Calendar options field grid. Used by both the create-flow card
   (wide chat panel — caps at 2 columns) and the editor's gear panel
   (narrow ~284px usable — collapses to 1 column). The 280px minmax
   value is chosen so 3 cols never fit at typical chat-panel widths
   (≤800px) and 2 cols don't fit at the narrow editor width — both
   contexts get a sensible auto-collapse without a media query. */
.calendar-options-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    /* Row gap is larger than column gap so the menu rows breathe
       vertically; columns stay tight so the two-column layout reads
       as a pair rather than two separate columns. */
    gap: 18px 14px;
}

.calendar-options-field {
    display: flex;
    flex-direction: column;
    /* Tight gap so the label sits close to its control. */
    gap: 2px;
}

.calendar-options-field-label {
    /* Slight indent so the label clears the pill's rounded corner
       without sitting all the way under the flat-edge start (16px =
       the border-radius). 12px aligns with the select's interior
       padding so label text and option text share a left edge. */
    padding-left: 12px;
    font-family: var(--font-main, Roboto);
    font-size: 12px;
    font-weight: 500;
    color: var(--color-text);
    opacity: 0.85;
    letter-spacing: 0.02em;
}

/* ==========================================================================
   Shared control styles: pill select, pill input, gradient pill button.
   Use the `.select-pill` / `.input-pill` / `.btn-gradient` utility classes
   on new components. Existing panel-specific class names are aliased via
   `:where()` so they inherit the same look without duplicating the rule
   per file.

   Wrappers: pair `.select-pill-wrap` (or any element with `position:
   relative` containing a `.select-pill`) with the chevron rule below.
   `.calendar-options-field:has(.calendar-options-select)` and
   `.reasoning-control` are the existing aliases.
   ========================================================================== */

:where(.select-pill, .input-pill, #chat-reasoning-mode, .calendar-options-select, .calendar-options-input, .photos-filter-bar input, .photos-filter-bar select, .chat-icon-btn) {
    height: 32px;
    padding: 0 12px;
    border: 1px solid var(--color-border);
    border-radius: 16px;
    background: var(--color-surface);
    color: var(--color-text);
    font-family: var(--font-main);
    font-size: 14px;
    transition: background-color 0.2s ease;
}

:where(.select-pill, #chat-reasoning-mode, .calendar-options-select, .photos-filter-bar select) {
    appearance: none;
    -webkit-appearance: none;
    padding-right: 28px;
    cursor: pointer;
    background-image: none;
}

:where(.select-pill, .input-pill, #chat-reasoning-mode, .calendar-options-select, .calendar-options-input, .photos-filter-bar input, .photos-filter-bar select, .chat-icon-btn):hover {
    background: var(--color-bg-alt);
}

:where(.select-pill, .input-pill, #chat-reasoning-mode, .calendar-options-select, .calendar-options-input, .photos-filter-bar input, .photos-filter-bar select, .chat-icon-btn):disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Dark theme uses a near-black `--color-border` (#101010 in
   `theme.css`) which is indistinguishable from the dark surface.
   Brighten the border on pill controls so the outline reads.
   Mirrors the original `html.theme-dark #chat-reasoning-mode`
   override that lived in `site-chat-panel.css` before consolidation. */
html.theme-dark :where(.select-pill, .input-pill, #chat-reasoning-mode, .calendar-options-select, .calendar-options-input, .photos-filter-bar input, .photos-filter-bar select, .chat-icon-btn) {
    border-color: #d9d9d9;
}

/* Chevron — lives on the wrapper so it overlays the select's right edge. */
:where(.select-pill-wrap, .reasoning-control, .calendar-options-field:has(.calendar-options-select), .photos-filter-select) {
    position: relative;
}

:where(.select-pill-wrap, .reasoning-control, .calendar-options-field:has(.calendar-options-select), .photos-filter-select)::after {
    content: '';
    position: absolute;
    pointer-events: none;
    right: 12px;
    /* `top: 50%` works for wrappers that contain only the select;
       `bottom: 14px` lines up with the bottom-anchored 32px control
       in `.calendar-options-field`, where a label sits above. */
    top: 50%;
    transform: translateY(-50%);
    border-width: 5px 4px 0 4px;
    border-style: solid;
    border-color: var(--color-text) transparent transparent transparent;
}

:where(.calendar-options-field:has(.calendar-options-select))::after {
    top: auto;
    bottom: 14px;
    transform: none;
}

/* Shared page and project spacing dialogs: centered, scrolling within the viewport. */
.site-dialog .modal-content:has(.spacing-dialog) {
    max-width: 480px;
    text-align: left;
    position: static;
    bottom: auto;
    max-height: min(88vh, 720px);
    overflow-y: auto;
}

.spacing-dialog__note {
    margin: 0 0 10px;
}

.spacing-dialog__note,
.spacing-dialog__scope-note {
    font-size: 12px;
    color: var(--color-text-muted);
}

.spacing-dialog__scope-note {
    margin: 0;
}

.spacing-dialog__terms {
    margin: 14px 0;
    padding: 0 0 0 18px;
    list-style: disc;
}

.spacing-dialog__term {
    padding: 4px 0;
    font-size: 13px;
    color: var(--color-text-muted);
}

.spacing-dialog__term strong {
    font-weight: 600;
    color: var(--color-text);
}

/* Keep punctuation outside translated terms. */
.spacing-dialog__term strong::after {
    content: ': ';
}

.spacing-dialog__fields {
    margin-bottom: 14px;
}

.spacing-dialog__scope {
    padding: 0;
}

.spacing-dialog__scope-row {
    display: flex;
    gap: 8px;
    padding: 8px 0;
}

.spacing-dialog__scope-row .icon {
    font-size: 20px;
    color: var(--color-accent-fg);
}

.spacing-dialog__scope-line {
    margin: 0;
    font-size: 13px;
    color: var(--color-text);
}

.spacing-dialog__scope-line strong {
    font-weight: 600;
}

.spacing-dialog__scope-detail {
    margin: 2px 0 0;
    font-size: 12px;
    color: var(--color-text-muted);
}

.site-dialog .modal-content:has(.spacing-dialog) .modal-actions .btn {
    min-width: 116px;
}

.site-dialog .modal-content:has(.spacing-dialog) .modal-actions {
    justify-content: flex-end;
}

/* Preserve the gradient on secondary Apply actions. */
.site-dialog .modal-actions .btn-cancel.btn-gradient {
    border: none;
    background-color: transparent;
    color: var(--color-text-on-gradient, #fff);
}

/* Gradient pill button. Aliases: `.rearrange-done`,
   `.calendar-options-submit`. */
:where(.btn-gradient, .rearrange-done, .calendar-options-submit) {
    appearance: none;
    border: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 32px;
    padding: 0 18px;
    border-radius: 999px;
    background: linear-gradient(
        180deg,
        var(--color-gradient-start) 0%,
        var(--color-gradient-end) 100%
    );
    color: var(--color-text-on-gradient, #fff);
    font-family: var(--font-main);
    font-size: 14px;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    white-space: nowrap;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
    box-shadow: none;
}

:where(.btn-gradient, .rearrange-done, .calendar-options-submit):hover:not(:disabled) {
    transform: translateY(-1px);
}

:where(.btn-gradient, .rearrange-done, .calendar-options-submit):disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

/* Face Groups Modal */
#rename-face-group-modal.modal-overlay {
    z-index: 5000;
    box-sizing: border-box;
    padding: max(16px, env(safe-area-inset-top)) 16px max(16px, env(safe-area-inset-bottom));
    align-items: center;
}

.face-group-modal-content {
    max-width: 560px;
    text-align: left;
    background: var(--color-bg-message) !important;
    max-height: calc(100vh - 32px);
    max-height: calc(100dvh - 32px);
    display: flex;
    flex-direction: column;
}

/* The people list / photo picker scroll INSIDE the dialog; contain stops
   the scroll from chaining to the book page when an edge is reached. */
.face-group-modal-content .modal-body {
    min-height: 0;
    max-height: min(70vh, 560px);
    max-height: min(70dvh, 560px);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
}

/* Page scroll is locked while the People dialog is open (touch pans on the
   dialog are additionally cancelled in site-face-groups.js). */
body.face-group-modal-open {
    overflow: hidden;
}

/* Base grid — always 3 columns; count-specific classes override.
   justify-content centers items when the row is not full. */
.face-groups-list {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    justify-content: center;
    gap: 16px;
    padding: 4px;
    margin-bottom: 16px;
}

/* 1 thumbnail — 3-column track but only one item; centre it */
.face-groups-list.one {
    grid-template-columns: repeat(3, 1fr);
    /* The single item occupies the middle column */
    justify-items: center;
}
.face-groups-list.one .face-group-row {
    grid-column: 2;
}

/* 2 thumbnails — 2 columns, centred */
.face-groups-list.two {
    grid-template-columns: repeat(2, 1fr);
}

/* 3 thumbnails — 3 columns, single row (default already works; explicit for clarity) */
.face-groups-list.three {
    grid-template-columns: repeat(3, 1fr);
}

/* 4–6 thumbnails — 3 columns, auto rows (default) */
/* No extra class needed for 4/5/6; base .face-groups-list handles them */

/* 7+ thumbnails — 3 columns, scrollable */
.face-groups-list.six-plus {
    grid-template-columns: repeat(3, 1fr);
    max-height: 420px;
    overflow-y: auto;
}

.face-group-row {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 12px 8px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background-color: var(--color-bg-alt);
    transition: border-color 0.2s ease, background-color 0.2s ease;
}

.face-group-row.drag-over {
    border-color: var(--color-accent);
    background-color: var(--color-bg-alt);
}

.face-group-keep-checkbox {
    position: absolute;
    top: 4px;
    right: 4px;
    z-index: 2;
    cursor: pointer;
}

.face-group-keep-checkbox input {
    cursor: pointer;
    width: 16px;
    height: 16px;
    accent-color: var(--color-gradient-start);
}

.face-group-merged-badge {
    position: absolute;
    bottom: -6px;
    right: -6px;
    width: 24px;
    height: 24px;
    background: var(--color-accent);
    color: white;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 2;
    border: 2px solid var(--color-surface-2);
    cursor: pointer;
}

.face-group-merged-faces-container {
    display: flex;
    gap: 4px;
    align-items: center;
    margin-left: 8px;
    flex-wrap: wrap;
}

.merged-face-thumb {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    object-fit: cover;
}

.face-group-unmerge-btn {
    width: 100%;
    height: 32px;
    padding: 4px;
    border-radius: 6px;
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text-muted);
    font-size: 11px;
    cursor: pointer;
    transition: all 0.2s ease;
}

.face-group-unmerge-btn:hover {
    background: var(--color-bg-alt);
    color: var(--color-text);
}



.face-group-label-input:focus {
    outline: none;
    border-color: var(--color-accent);
}

.face-group-name-field {
    position: relative;
    width: 100%;
}

.face-group-label-input {
    width: 100%;
    height: 32px;
    padding: 6px 10px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-surface);
    color: var(--color-text);
    font-size: 13px;
    text-align: center;
    box-sizing: border-box;
}

.face-group-name-suggestions {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    display: none;
    max-height: 180px;
    overflow-y: auto;
    padding: 4px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-surface);
    box-shadow: 0 12px 30px rgba(0, 0, 0, 0.16);
    z-index: 20;
}

.face-group-name-suggestions.visible {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.face-group-name-suggestion {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-height: 36px;
    padding: 6px 8px;
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: var(--color-text);
    font: inherit;
    font-size: 13px;
    text-align: left;
    cursor: pointer;
}

.face-group-name-suggestion:hover,
.face-group-name-suggestion:focus {
    outline: none;
    background: var(--color-bg-alt);
}

.face-group-name-suggestion-thumb {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
}

.face-group-name-suggestion-label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}





/* Relation select wrapper — position: relative always needed for the chevron overlay;
   the ::after chevron only renders when the inner select is visible. */
.face-relation-select-wrap {
    position: relative;
    width: 100%;
}

.face-relation-select-wrap:has(.face-group-relation-select.visible)::after {
    content: '';
    position: absolute;
    pointer-events: none;
    right: 12px;
    top: 50%;
    transform: translateY(-50%);
    border-width: 5px 4px 0 4px;
    border-style: solid;
    border-color: var(--color-text) transparent transparent transparent;
}

.face-group-relation-select {
    width: 100%;
    height: 32px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-surface);
    color: var(--color-text);
    font-size: 12px;
    box-sizing: border-box;
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    /* transition for sliding down */
    max-height: 0;
    opacity: 0;
    margin-top: 0;
    padding: 0 10px;
    border-width: 0;
    overflow: hidden;
    transition: all 0.3s ease;
}

.face-group-relation-select.visible {
    height: 32px;
    max-height: 32px;
    opacity: 1;
    margin-top: 4px;
    padding: 4px 28px 4px 10px;
    border-width: 1px;
}

.face-group-relation-select:focus {
    outline: none;
    border-color: var(--color-accent);
}

/* Wrapper and Overlay for Undo */
.face-group-thumb-wrapper {
    position: relative;
    width: 80px;
    height: 80px;
    border-radius: 50%;
}

.face-group-thumb {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
    border: 2px solid var(--color-border);
    transition: opacity 0.3s ease;
}

.face-group-stacked-thumb {
    position: absolute;
    top: 0;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
    border: 2px solid var(--color-border);
    box-shadow: -2px 0 4px rgba(0,0,0,0.2);
}

/* Persistent aggregation stacks (saved state) peek from BEHIND the person's
   profile face; session merge thumbs continue to land on top so the user sees
   the face they just dragged. Layering: persistent stack (1) < primary thumb
   (2) < session merge thumbs (3-5, inline) < count badge (6) < change-photo
   button (7). */
.face-group-thumb-wrapper .face-group-thumb {
    position: relative;
    z-index: 2;
}

.face-group-stacked-thumb[data-persistent-stack] {
    z-index: 1 !important;
}

/* Bounded image-only container for a persistent stack crop: the shared image
   failure handler positions its overlay against the parent, so each crop gets
   its own circle rather than sharing the row's whole thumb wrapper. */
.face-group-stacked-thumb-wrap {
    position: absolute;
    top: 0;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    overflow: hidden;
    z-index: 1;
}

.face-group-stacked-thumb-wrap .face-group-stacked-thumb {
    position: absolute;
    top: 0;
    left: 0 !important;
    width: 100%;
    height: 100%;
}

/* A hidden person's whole card dims, stack included. */
.face-group-row.removed .face-group-stacked-thumb {
    opacity: 0.3;
}

.face-group-stacked-count {
    position: absolute;
    right: -12px;
    bottom: 2px;
    z-index: 6;
    min-width: 26px;
    height: 26px;
    padding: 0 6px;
    border: 2px solid var(--color-bg-alt);
    border-radius: 999px;
    background: var(--color-surface);
    color: var(--color-text);
    font-size: 11px;
    font-weight: 700;
    line-height: 22px;
    text-align: center;
    box-shadow: 0 2px 8px rgba(0,0,0,0.24);
    box-sizing: border-box;
}

.face-group-thumb-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease;
}

.face-group-undo-btn {
    background: rgba(255, 255, 255, 0.2);
    border: 1px solid rgba(255, 255, 255, 0.5);
    border-radius: 50%;
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: white;
    cursor: pointer;
    pointer-events: auto;
    transition: background 0.2s;
}

.face-group-undo-btn:hover {
    background: rgba(255, 255, 255, 0.4);
}

.face-group-undo-btn svg {
    width: 18px;
    height: 18px;
}

.face-group-removed-text {
    display: none;
    font-size: 11px;
    letter-spacing: 1px;
    color: var(--color-text-muted);
    font-weight: 600;
    text-transform: uppercase;
    text-align: center;
    margin-top: auto;
    margin-bottom: auto;
}

/* Change-profile-photo button on the modal thumbnail */
.face-group-change-photo-btn {
    position: absolute;
    right: -2px;
    bottom: -2px;
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text-muted);
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.2s ease, color 0.2s ease;
    /* Above session merge thumbs (3-5) and the count badge (6). */
    z-index: 7;
}

.face-group-change-photo-btn .icon {
    font-size: 15px;
}

.face-group-thumb-wrapper:hover .face-group-change-photo-btn,
.face-group-change-photo-btn:focus-visible {
    opacity: 1;
}

/* Touch devices have no hover — keep the affordance visible */
@media (hover: none) {
    .face-group-change-photo-btn {
        opacity: 1;
    }
}

.face-group-change-photo-btn:hover {
    color: var(--color-text);
}

.face-group-row.removed .face-group-change-photo-btn {
    display: none;
}

/* Profile-photo picker view inside the People modal */
.face-group-photo-picker-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;
}

.face-group-photo-picker-back {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-surface);
    color: var(--color-text);
    font: inherit;
    font-size: 13px;
    padding: 4px 10px;
    cursor: pointer;
}

.face-group-photo-picker-back:hover,
.face-group-photo-picker-back:focus-visible {
    background: var(--color-bg-alt);
}

.face-group-photo-picker-back .icon {
    font-size: 16px;
}

.face-group-photo-picker-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--color-text);
}

.face-group-photo-picker-grid {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px;
    max-height: 320px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    padding: 2px;
}

.face-group-photo-picker-status {
    font-size: 13px;
    color: var(--color-text-muted);
    margin: 4px 0;
}

.face-group-photo-option {
    position: relative;
    width: 72px;
    height: 72px;
    padding: 0;
    border: 2px solid var(--color-border);
    border-radius: 50%;
    background: var(--color-bg-alt);
    cursor: pointer;
    flex-shrink: 0;
    transition: border-color 0.2s ease, transform 0.2s ease;
}

.face-group-photo-option:hover,
.face-group-photo-option:focus-visible {
    border-color: var(--color-accent);
    transform: scale(1.04);
}

.face-group-photo-option.is-current {
    border-color: var(--color-accent);
}

.face-group-photo-option.is-saving {
    opacity: 0.5;
    pointer-events: none;
}

.face-group-photo-picker.is-saving .face-group-photo-option {
    pointer-events: none;
}

.face-group-photo-crop {
    position: absolute;
    inset: 0;
    display: block;
    border-radius: 50%;
    overflow: hidden;
}

.face-group-photo-crop img {
    position: absolute;
    top: 0;
    left: 0;
    max-width: none;
}

.face-group-photo-current-tick {
    position: absolute;
    right: -2px;
    bottom: -2px;
    width: 20px;
    height: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--color-accent);
    color: white;
    font-size: 12px;
    pointer-events: none;
}

/* Removed State */
.face-group-row.removed .face-group-name-field,
.face-group-row.removed .face-group-relation-select,
.face-group-row.removed .face-group-unmerge-btn,
.face-group-row.removed .face-group-merged-badge {
    display: none !important;
}

.face-group-row.removed .face-relation-select-wrap::after {
    content: none;
    display: none;
}

.face-group-row.removed .face-group-thumb {
    opacity: 0.3;
}

.face-group-row.removed .face-group-removed-text {
    display: block;
}
.face-group-modal-content .btn-primary { background: var(--gradient-bright-blue); color: white; border: none; }
.face-group-modal-content .btn-cancel {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    color: var(--color-text);
    font-weight: normal;
}

.face-group-modal-content .btn-cancel:hover,
.face-group-modal-content .btn-cancel:focus-visible {
    background: rgba(var(--shadow-color-rgb) / 0.08);
}

@media (max-width: 640px) {
    #rename-face-group-modal.modal-overlay {
        padding: max(12px, env(safe-area-inset-top)) 12px max(12px, env(safe-area-inset-bottom));
    }

    .face-group-modal-content {
        width: min(100%, calc(100vw - 24px));
        max-height: calc(100vh - 24px);
        max-height: calc(100dvh - 24px);
        padding: 16px;
    }

    .face-group-modal-content .modal-body {
        max-height: none;
    }

    .face-groups-list,
    .face-groups-list.six-plus {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 12px;
        max-height: none;
    }

    .face-groups-list.one {
        grid-template-columns: 1fr;
    }

    .face-groups-list.one .face-group-row {
        grid-column: 1;
    }
}

/* Admin act-as support banner (templates/components/admin_act_as_banner.html).
   Fixed above every surface so an impersonating admin can never mistake whose
   account they are editing. Tokens keep light/dark handled by theme.css. */
.admin-act-as-banner {
    position: fixed;
    /* Above any bar docked to the foot of the screen. The projects pager is
       one on phones, and this banner paints over everything at z-index 10050,
       so it would swallow the taps meant for the page controls. */
    bottom: calc(16px + var(--app-bottom-dock-height, 0px));
    left: 16px;
    z-index: 10050;
    display: flex;
    align-items: center;
    gap: 8px;
    max-width: min(92vw, 560px);
    padding: 8px 12px;
    border: 1px solid var(--color-amber);
    border-radius: 999px;
    background: var(--color-surface);
    color: var(--color-text);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);
    font-size: 0.85rem;
}

.admin-act-as-banner .icon {
    color: var(--color-amber);
    font-size: 20px;
}

.admin-act-as-banner__target {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--color-text-muted);
    font-size: 0.78rem;
}

.admin-act-as-banner__exit {
    flex-shrink: 0;
    padding: 4px 12px;
    border: 1px solid var(--color-border-strong);
    border-radius: 999px;
    background: var(--color-surface-alt);
    color: var(--color-text);
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
}

.admin-act-as-banner__exit:hover {
    border-color: var(--color-accent);
}

@media (max-width: 640px) {
    .admin-act-as-banner__target {
        display: none;
    }
}

/* Full-page lock shown when the act-as session this tab was rendered for
   ended (TTL expiry) or was superseded by opening another customer's
   project — further edits would run under the wrong identity. */
.admin-act-as-ended {
    position: fixed;
    inset: 0;
    /* Above every interactive editor chrome layer — Coloris (11000) and the
       shared site dialogs (11500) — so an open picker or modal cannot keep
       issuing edits after the session lock engages. Only the inert
       .instant-tooltip (12000) may paint above this. */
    z-index: 13000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.55);
}

.admin-act-as-ended[hidden] {
    display: none;
}

.admin-act-as-ended__card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    max-width: min(92vw, 420px);
    padding: 28px 32px;
    border: 1px solid var(--color-amber);
    border-radius: 16px;
    background: var(--color-surface);
    color: var(--color-text);
    text-align: center;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35);
}

.admin-act-as-ended__card .icon {
    color: var(--color-amber);
    font-size: 32px;
}

.admin-act-as-ended__card h2 {
    margin: 0;
    font-size: 1.1rem;
}

.admin-act-as-ended__card p {
    margin: 0;
    color: var(--color-text-muted);
    font-size: 0.9rem;
}

.admin-act-as-ended__card .btn-gradient {
    text-decoration: none;
}
