:root {
    color-scheme: light;
    font-family: "Roboto", "Segoe UI", Arial, sans-serif;
    background: #f9f9ff;
    color: #1a1b20;

    /* Material 3 light palette from the blue seed, like the Flutter app
       (ThemeData(colorSchemeSeed: Colors.blue, useMaterial3: true)). */
    --md-primary: #415f91;
    --md-on-primary: #ffffff;
    --md-primary-hover: #385380;
    --md-primary-container: #d6e3ff;
    --md-on-primary-container: #001b3e;
    --md-secondary-container: #dae2f9;
    --md-on-secondary-container: #131c2b;
    --md-surface: #f9f9ff;
    --md-surface-container-low: #f3f3fa;
    --md-surface-container: #ededf4;
    --md-outline: #74777f;
    --md-outline-variant: #c4c6d0;
    --md-on-surface: #1a1b20;
    --md-on-surface-variant: #44474e;
    --sheet-bg: #f0f2f9;
    --app-top-bar-height: 58px;

    /* Neutral text/border greys and accents reused across the app (the second,
       Google-derived palette that sits alongside the M3 tokens above). */
    --text-body: #202124;
    --text-secondary: #3c4043;
    --text-muted: #5f6368;
    --eyebrow: #60746c;
    --input-border: #dadce0;
    --accent-blue: #1a73e8;
    --accent-blue-bg: #e8f0fe;
    --error-text: #b3261e;
    /* Hover wash tints: --primary-tint is the M3 primary (#415f91) at 8%. */
    --primary-tint: rgba(65, 95, 145, 0.08);
    --neutral-tint: rgba(60, 64, 67, 0.08);
    /* Photo column height plus tile padding; used by the listing scroll tail. */
    --listing-tile-min-height: calc(5.5rem + 6px);
}

html,
body,
#app {
    height: 100%;
    overflow: hidden;
}

body {
    margin: 0;
    font-family: "Roboto", "Segoe UI", Arial, sans-serif;
}

h1:focus,
h1:focus-visible {
    outline: none;
}

.app-shell button,
.app-shell input {
    font: inherit;
}

.app-command {
    border: 1px solid var(--md-primary);
    border-radius: 0.875rem;
    background: var(--md-primary);
    color: var(--md-on-primary);
    cursor: pointer;
    min-height: 1.75rem;
    padding: 0 0.875rem;
}

.app-command:disabled {
    cursor: default;
    opacity: 0.65;
}

/* M3 OutlinedButton. */
.secondary-command {
    align-items: center;
    background: transparent;
    border: 1px solid var(--md-outline);
    border-radius: 0.875rem;
    color: var(--md-primary);
    cursor: pointer;
    display: inline-flex;
    font-weight: 500;
    gap: 0.4rem;
    justify-content: center;
    min-height: 1.75rem;
    padding: 0 0.7rem;
    text-decoration: none;
}

.secondary-command:hover,
.secondary-command:focus-visible {
    background: var(--primary-tint);
    outline: none;
}

.new-offer-start-content,
.new-offer-start-options,
.account-management-content,
.account-management-options {
    display: grid;
    gap: 0.5rem;
}

.new-offer-start-content .form-section,
.account-management-content .form-section {
    gap: 0.5rem;
}

.new-offer-start-label,
.account-management-label {
    color: var(--md-primary);
    font-size: var(--app-font-size-label);
}

/* The delete-account launcher supplies its own Material Symbols glyph (fingerprint_off, as in the
   ingress). The font's own class sets 24px on the glyph itself, so the size the field lane expects
   has to be restated on the content this sheet passes in. */
.account-management-options .material-symbols-outlined {
    font-size: 18px;
}

.app-shell {
    background: var(--md-surface);
    display: flex;
    flex-direction: column;
    font-family: inherit;
    height: 100dvh;
}

.app-shell:fullscreen,
.app-shell:-webkit-full-screen {
    background: var(--md-surface);
}

.app-shell > .buyer-home {
    flex: 1;
    min-height: 0;
}

.buyer-home > .main-page {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}

main.main-page {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 0.75rem 1rem 1rem;
}

main.main-page > * {
    margin-left: auto;
    margin-right: auto;
    max-width: 72rem;
}

/* The map page fills the whole viewport like the Flutter Scaffold body. */
main.main-map {
    display: flex;
    flex: 1;
    flex-direction: column;
    min-height: 0;
    min-width: 0;
    overflow-x: clip;
    padding: 0;
}

.buyer-home {
    display: flex;
    flex: 1;
    flex-direction: column;
    min-height: 0;
    position: relative;
}

/* Favourites use the same clipped slide track as the map/list toggle. On narrow
   screens the favourites panel and home surface are adjacent pages; wide screens overlay the panel. */
.home-surface {
    display: flex;
    flex: 0 0 100%;
    flex-direction: column;
    min-height: 0;
}

.favourites-slide-viewport {
    flex: 1;
    min-width: 0;
    overflow-x: clip;
}

.favourites-slide-track > .favourites-side-panel,
.favourites-slide-track > .home-surface {
    flex: 0 0 100%;
    min-height: 0;
    min-width: 0;
}

.favourites-slide-track.show-favourites {
    transform: translateX(0);
}

.favourites-slide-track.show-home {
    transform: translateX(-100%);
}

.favourites-side-panel {
    background: var(--md-surface);
    display: flex;
    flex-direction: column;
    min-height: 0;
    width: 100%;
}

.favourites-panel {
    display: flex;
    flex: 1;
    flex-direction: column;
    min-height: 0;
}

.favourites-panel-header {
    align-items: center;
    display: flex;
    flex: 0 0 auto;
    justify-content: space-between;
    padding: 0.625rem 0.75rem 0.5rem 1rem;
}

.favourites-panel-header h2 {
    color: var(--text-body);
    font-size: 1.125rem;
    font-weight: 600;
    line-height: 1.25;
    margin: 0;
}

.favourites-panel-header .icon-command {
    flex: 0 0 auto;
}

.favourites-panel-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 0.25rem 0.75rem 1rem;
}

.favourites-panel-new-offer {
    display: flex;
    gap: 0.5rem;
    justify-content: flex-end;
    margin-bottom: 0.75rem;
}

.favourites-panel-section {
    display: grid;
    gap: 0.5rem;
}

.favourites-panel-section + .favourites-panel-section {
    margin-top: 1rem;
}

.favourites-panel-section h3 {
    font-size: 0.95rem;
    font-weight: 700;
    margin: 0;
}

/* Minu müügikohad rows. A place is not a listing -- it has no seller, no availability window and no
   payment marks -- so it gets its own row rather than a listing tile with those columns left empty
   ([[uc_app_seller_mydrafts]]). The surface and hover match the tile beside it so the panel still
   reads as one list. */
.spot-list {
    display: grid;
    gap: 0.5rem;
    grid-template-columns: minmax(0, 1fr);
    min-width: 0;
}

.app-spot-row {
    background: var(--app-listing-surface);
    border: 0;
    border-radius: 0.75rem;
    box-shadow: 0 1px 3px var(--app-listing-shadow);
    box-sizing: border-box;
    cursor: pointer;
    display: grid;
    gap: 0.125rem;
    min-width: 0;
    padding: 0.5rem 0.625rem;
    width: 100%;
}

.app-spot-row:hover,
.app-spot-row:focus-visible {
    background: var(--app-listing-highlight-surface);
    box-shadow: inset 0 0 0 1px var(--app-listing-highlight-ring), 0 1px 3px var(--app-listing-shadow);
    outline: none;
}

.app-spot-row-header {
    align-items: center;
    display: flex;
    gap: 0.375rem;
    min-width: 0;
}

.app-spot-row-header h4 {
    color: var(--md-on-surface);
    font-size: 0.9rem;
    font-weight: 700;
    line-height: 1.2;
    margin: 0;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.app-spot-row-meta {
    align-items: center;
    color: var(--md-on-surface-variant);
    display: flex;
    font-size: var(--app-font-size-label);
    font-weight: var(--app-font-weight-regular);
    gap: 0.25rem;
    line-height: 1.15rem;
    min-width: 0;
}

.app-spot-row-meta > span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

@media (min-width: 601px) {
    .favourites-slide-track.show-favourites,
    .favourites-slide-track.show-home {
        position: relative;
        transform: none;
    }

    .favourites-slide-track > .home-surface {
        flex-basis: 100%;
    }

    .favourites-slide-track > .favourites-side-panel {
        bottom: 0;
        left: 0;
        position: absolute;
        top: 0;
        transform: translateX(-100%);
        /* min() already caps the panel, so the width is the only place the figure is written. */
        width: min(400px, 100%);
        z-index: 1;
    }

    .favourites-slide-track.show-favourites > .favourites-side-panel {
        transform: translateX(0);
        transition: transform 0.42s ease;
    }
}

.icon-command {
    align-items: center;
    background: transparent;
    border: none;
    border-radius: 50%;
    color: var(--text-muted);
    cursor: pointer;
    display: inline-flex;
    height: 2.5rem;
    justify-content: center;
    padding: 0;
    position: relative;
    width: 2.5rem;
}

.hover-wash,
.icon-command:hover,
.icon-command:focus-visible {
    background: #f1f3f4;
    outline: none;
}

.icon-command[aria-pressed="true"],
.icon-command.is-selected {
    background: var(--accent-blue-bg);
    color: var(--accent-blue);
}

/* Map fills all remaining viewport height, edge to edge, like FlutterMap. */
.map-panel {
    background: #dce9e2;
    flex: 1;
    min-height: 0;
    overflow: hidden;
    position: relative;
    /* Trap Leaflet's own control panes (zoom, attribution -- z-index ~400-1000)
       inside this stacking context so they stay below the app chrome overlays
       (account menu z-index 60/61, bottom sheets 50). */
    isolation: isolate;
}

/* The embedded Common26.MapLib component renders a `.map-component-shell` root (and an
   inner OpenLayers div). Neither class appears in this app's own markup, so it reads as
   "unused" from an App-only search — but the host owns sizing it: without height:100%
   the shell collapses to 0 and the map fails to initialize ("No map visible because the
   map container's width or height are 0"). Do not remove. */
.map-panel .map-component-shell,
.map-panel .map-component-shell > div:first-child > div {
    height: 100%;
}

/* The failed boot's own message, rendered by the home page in place of its content when the sheet
   layer cannot render one (uc_app_public_loading). It stands in for the whole content area, so it
   takes the same flex share the viewport would have taken. */
.boot-failure {
    align-content: center;
    flex: 1;
    min-height: 0;
    padding: 1.5rem;
    text-align: center;
}

.boot-failure-title {
    color: var(--text-body);
    font-size: 1.125rem;
    font-weight: 500;
    margin: 0 0 0.5rem;
}

.boot-failure-message {
    color: var(--error-text);
    margin: 0;
}

/* Map and list remain mounted so the map keeps its live state. On narrow view,
   the listing panel moves over the stationary map; app bars and FAB stay put
   because they are siblings outside this viewport. */
.slide-viewport {
    flex: 1;
    min-height: 0;
    overflow-x: hidden;
    position: relative;
}

.slide-track {
    display: flex;
    height: 100%;
    width: 100%;
}

.favourites-slide-track {
    will-change: transform;
}

@media (max-width: 600px) {
    .favourites-slide-track.show-favourites {
        transition: transform 0.42s ease;
    }
}

.map-list-track > .map-panel,
.map-list-track > .listing-panel {
    flex: 0 0 100%;
    min-height: 0;
    min-width: 0;
}

@media (min-width: 601px) {
    .map-list-track.show-list {
        position: relative;
        transform: translateX(0);
    }

    .map-list-track.show-list > .map-panel {
        flex-basis: 100%;
    }

    .map-list-track.show-list > .listing-panel {
        background: transparent;
        height: 100%;
        max-width: 28.8rem;
        padding: 0.75rem;
        position: absolute;
        right: 0;
        top: 0;
        width: 28.8rem;
        z-index: 1;
        /* As an overlay on the map the panel spans the full height, but only tiles should block
           the map. Let events pass through the transparent panel and list grid, then re-enable
           them on tiles so empty space below a short list keeps the map interactive. */
        pointer-events: none;
    }

    .map-list-track.show-list > .listing-panel > .listing-list {
        pointer-events: none;
    }

    .map-list-track.show-list > .listing-panel > .listing-list > * {
        pointer-events: auto;
    }

    /* Uudised takes the same right-hand column the listing overlay occupies, so switching between
       them moves nothing sideways. */
    .slide-viewport > .news-panel {
        left: auto;
        padding: 0.75rem;
        width: 28.8rem;
    }
}

@media (max-width: 600px) {
    .map-list-track {
        position: relative;
    }

    .map-list-track > .listing-panel {
        bottom: 0;
        left: 0;
        position: absolute;
        right: 0;
        top: 0;
        will-change: transform;
    }

    .map-list-track.show-map > .listing-panel {
        pointer-events: none;
        transform: translateX(100%);
    }

    .map-list-track.show-list > .listing-panel {
        background: transparent;
        /* Match the wide overlay: tiles remain interactive, while the transparent space around
           them leaves the stationary map visible and usable. */
        pointer-events: none;
        transform: translateX(0);
        transition: transform 0.42s ease;
    }

    /* The strips are an overlay on a live map, so their width is also how much map they cover.
       Holding 85% of the panel's content box takes 15% off every strip; the auto start margin
       spends all of it on the same side, so the strips keep the trailing edge they line up on
       and the map opens up in one band rather than two thin ones. */
    .map-list-track.show-list > .listing-panel > .listing-list {
        margin-left: auto;
        max-width: 85%;
        pointer-events: none;
    }

    .map-list-track.show-list > .listing-panel > .listing-list > * {
        pointer-events: auto;
    }

    /* The same 85% strips as the listing overlay, so the map keeps one open band down the leading
       edge rather than being covered edge to edge. */
    .news-panel > .listing-list {
        margin-left: auto;
        max-width: 85%;
    }
}

@media (prefers-reduced-motion: reduce) {
    .slide-track {
        transition: none;
    }

    .home-surface,
    .favourites-side-panel {
        animation: none;
        transition: none;
    }
}

/* AppTopBar's bottom control strip is trailing-aligned and expects its consumer to mark the one
   command that belongs at the leading edge: the auto end-margin takes the slack, so this command
   sits at the left and everything after it collects at the right. The fullscreen control is the
   leftmost item of the strip in both states (uc_app_public_fullscreen). */
.strip-leading {
    margin-inline-end: auto;
}

.role-segment {
    border: 1px solid #747775;
    border-radius: 0.875rem;
    box-sizing: border-box;
    display: inline-grid;
    flex: 0 0 auto;
    grid-template-columns: auto auto;
    height: 1.75rem;
    overflow: hidden;
    width: fit-content;
}

.role-segment-button {
    align-items: center;
    background: transparent;
    border: 0;
    color: #444746;
    cursor: pointer;
    display: flex;
    font-size: 0.875rem;
    font-weight: 500;
    gap: 0.5rem;
    height: 100%;
    justify-content: center;
    line-height: 1;
    min-width: 0;
    padding: 0 0.9rem;
}

.role-segment-button + .role-segment-button {
    border-left: 1px solid #747775;
}

.role-segment-button.is-selected {
    background: var(--md-secondary-container);
    color: var(--md-on-secondary-container);
}

/* Modal bottom sheets, like Flutter's showModalBottomSheet. */
@keyframes scrim-fade-in {
    from {
        opacity: 0;
    }
}

@keyframes scrim-fade-out {
    to {
        opacity: 0;
    }
}

.sheet-scrim {
    animation: scrim-fade-in 0.25s ease;
    background: rgba(0, 0, 0, 0.35);
    inset: 0;
    position: fixed;
    /* Smooths modal <-> map-preserving transitions and narrow <-> wide resizes. */
    transition: background 0.25s ease;
    z-index: 40;
}

/* Map-preserving sheets: on wide view the filter and detail/group sheets are
   non-modal so the map behind them stays live (pan, zoom, marker and tile taps
   hand off between sheets through the coordinator). Their mounted scrim loses
   its dim and click-blocking. Narrow view stays modal.
   Keyed off the App's own panel class, which only a sheet ever carries. */
.app-shell:has(.spot-data-panel) .sheet-scrim,
.app-shell:has(.detail-panel) .sheet-scrim {
    background: rgba(0, 0, 0, 0);
    pointer-events: none;
}

.filter-panel {
    display: block;
    font-size: 0.875rem;
}

.filter-panel-header {
    align-items: center;
    display: grid;
    grid-template-columns: minmax(0, 17.25rem) 1fr;
    gap: 0.75rem;
    margin-bottom: calc(1rem - 10px);
}

.filter-panel-header-search {
    min-width: 0;
}

/* Keep the header actions pinned right while the search stays left aligned. */
.filter-panel-header-actions {
    align-items: center;
    display: flex;
    gap: 0.5rem;
    justify-self: end;
}

.filter-panel .filter-result-summary {
    align-items: end;
    display: flex;
    flex-direction: column;
}

.filter-panel .filter-result-count,
.filter-panel .filter-result-limit {
    color: var(--md-on-surface-variant);
    font-size: 0.75rem;
    white-space: nowrap;
}

.filter-panel .filter-result-link {
    background: transparent;
    border: 0;
    border-radius: 0.25rem;
    color: var(--md-on-surface-variant);
    cursor: pointer;
    font: inherit;
    padding: 0.125rem 0.25rem;
    text-decoration: none;
}

.filter-panel .filter-result-link:hover {
    background: rgba(0, 0, 0, 0.12);
}

.filter-panel .text-command {
    border-radius: 0.875rem;
    font-size: 0.8125rem;
    gap: 0.25rem;
    min-height: 1.6rem;
    padding: 0 0.45rem;
}

.filter-panel .filter-section {
    margin-bottom: calc(1rem - 10px);
}

.filter-panel .filter-section:last-of-type {
    margin-bottom: 0;
}

.filter-panel .filter-hint {
    color: rgba(0, 0, 0, 0.54);
    font-size: 0.75rem;
    line-height: 1rem;
}

.filter-panel .filter-note {
    font-size: 0.75rem;
    margin: 0.5rem 0 0;
}

.text-command {
    align-items: center;
    background: none;
    border: 0;
    border-radius: 0.875rem;
    color: var(--md-primary);
    cursor: pointer;
    display: inline-flex;
    font-size: 0.875rem;
    font-weight: 500;
    gap: 0.4rem;
    min-height: 1.75rem;
    padding: 0 0.5rem;
}

.text-command:hover,
.text-command:focus-visible {
    background: var(--primary-tint);
    outline: none;
}

.count-badge {
    align-items: center;
    background: var(--md-primary);
    border-radius: 999px;
    color: var(--md-on-primary);
    display: inline-flex;
    font-size: 0.7rem;
    font-weight: 700;
    height: 1.1rem;
    justify-content: center;
    min-width: 1.1rem;
    padding: 0 0.25rem;
}

.filter-section {
    display: grid;
    gap: 0;
}

.filter-hint {
    color: var(--md-on-surface-variant);
    font-size: 0.75rem;
    margin: 0;
}

/* Layout slot for the field-clear AppIconButton; the button owns its own (compact) size. */
.search-clear {
    align-items: center;
    display: inline-flex;
    flex: 0 0 auto;
}

.filter-note {
    color: var(--md-on-surface-variant);
    margin: 0.75rem 0;
}

.panel {
    background: #fff;
    border: 1px solid #d6ddd7;
    border-radius: 8px;
    padding: 1rem;
}

.panel h2 {
    margin-top: 0;
}

.listing-panel {
    background: var(--md-surface);
    box-sizing: border-box;
    container-type: size;
    flex: 1;
    margin: 0;
    max-width: none;
    min-height: 0;
    min-width: 0;
    overflow-x: clip;
    overflow-y: auto;
    padding: 0.75rem 0.75rem 6rem;
    -ms-overflow-style: none;
    scrollbar-width: none;
    /* none: the panel is grabbed and drag-scrolled like a sheet; a mouse drag
       must scroll, not select tile text. Scrollbar is hidden; touch, wheel, and
       bindListDragScroll still move the list. */
    -webkit-user-select: none;
    user-select: none;
    width: 100%;
}

.listing-panel::-webkit-scrollbar {
    display: none;
}

.buyer-home > .panel {
    margin: 0.75rem;
}

.listing-list {
    display: grid;
    gap: 0.5rem;
    grid-template-columns: minmax(0, 1fr);
    min-width: 0;
}

.listing-list > * {
    min-width: 0;
}

/* Trailing slack so a short list still scrolls: the last tile can reach the top of the panel while
   staying fully on screen. Tail height = panel height - one tile - vertical padding. */
.listing-panel > .listing-list::after {
    content: '';
    display: block;
    height: max(0px, calc(100cqh - var(--listing-tile-min-height) - 0.75rem - 6rem));
    pointer-events: none;
}

@media (min-width: 601px) {
    .map-list-track.show-list > .listing-panel > .listing-list::after {
        height: max(0px, calc(100cqh - var(--listing-tile-min-height) - 1.5rem));
    }
}

.detail-panel .app-sheet-body {
    display: grid;
    gap: calc(1rem - 5px);
}

.detail-label {
    color: var(--eyebrow);
    font-size: 0.75rem;
}

.listing-data-summary-card /* The calendar thumbnail is not an image: it brings its own 88px box, and its ring is drawn
   outside that box. An inset ring would only show through the 1px gaps between the day cells,
   which reads as specks of border rather than as a highlight. */
.listing-data-calendar-button {
    background: var(--app-surface-white, #fff);
    border: 0;
    cursor: pointer;
    display: block;
    flex: 0 0 88px;
    line-height: 0;
    padding: 0;
}

/* Hover dims it, the way a photo or a QR code dims under the pointer — no ring: an inset one
   would only show through the gaps between the day cells. Keyboard focus still needs a mark of
   its own, so that one keeps a ring, drawn outside the box. */
/* The button carries the ground the grid's 1px gaps show, so hovering dims the whole 88px square
   as one surface. A transparent button would leave those gaps bright and the dimming would read as
   something lying behind the calendar rather than as the calendar itself. */
.listing-data-calendar-button:hover {
    filter: brightness(0.82);
}

.listing-data-calendar-button:focus-visible {
    outline: 2px solid var(--md-primary);
    outline-offset: 2px;
}

.summary-card-photo-placeholder {
    cursor: default;
}

/* Availability and status use the same two-column grid as seller contacts. When published offers
   omit the status, availability owns the full card width instead of leaving an empty second column.
   The rows sit tighter than the columns: side by side the two facts need the full gap to read as
   separate columns, stacked they only have to separate one label/value pair from the next.
   Kirjeldus is not a grid child: it clears the floated corner actions so it gets a full-width row
   below the buttons instead of wrapping in the float lane beside them. */
.listing-data-detail-grid {
    column-gap: 0.75rem;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    margin-top: calc(0.35rem - 2px);
    row-gap: calc(0.75rem - 2px);
}

.listing-data-detail-grid > div {
    display: grid;
    gap: calc(0.2rem - 2px);
}

.listing-data-detail-description {
    clear: right;
    display: grid;
    gap: calc(0.2rem - 2px);
    margin-top: calc(0.35rem - 2px);
}

.listing-data-detail-grid + .listing-data-detail-description {
    margin-top: calc(0.75rem - 2px);
}

/* Every line of the Pakkumise kehtivus card speaks in the same voice as the window above it, so
   this one takes the subtext size and colour while keeping its own icon row. */
.listing-data-limited-amount-notice {
    align-items: center;
    color: var(--text-muted);
    display: flex;
    font-size: 0.8rem;
    gap: 0.35rem;
}

.listing-data-detail-grid-without-status > :first-child {
    grid-column: 1 / -1;
}

/* Seller info sheet uses the same label/value grid as the Detailid card. The web-links row spans
   the full width because it can hold up to three links in its own inner contact grid. */
.seller-info-detail-grid {
    column-gap: 0.75rem;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    margin-top: calc(0.35rem - 2px);
    row-gap: calc(0.75rem - 2px);
}

.seller-info-detail-grid > div {
    display: grid;
    gap: calc(0.2rem - 2px);
}

.seller-info-detail-grid > .seller-info-detail-web {
    grid-column: 1 / -1;
}

.group-list {
    display: grid;
    gap: 0.5rem;
}

/* All footer actions share one wrapping row, so they take a second line only when the first one is
   full — grouping them into separate rows used to split them while they still fit side by side. */
.listing-data-action-rows {
    display: flex;
    flex: 1 1 auto;
    flex-wrap: wrap;
    gap: 0.5rem;
    min-width: 0;
}

/* The card actions float to the top right of the text column, so only the lines actually level with
   them are shortened. Reserving a fixed gutter instead (padding-right) narrowed every line below the
   buttons as well, which is what made short titles and prices wrap. */
/* The seller card leads with the name and the rating on one line; the rating keeps to the right so
   the two read as one header even when a long seller name wraps under it. */
.listing-data-seller-head {
    align-items: center;
    column-gap: 0.75rem;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    row-gap: 0.35rem;
}

/* The contact channels flow as many to a row as fit, so the card stays short. Fixed columns split a
   value that was only a little too wide for half the card -- a phone number lost its last digits to
   the next line -- so a channel is sized by its own value and moves to the next row whole. */
.listing-data-seller-contacts {
    column-gap: 0.75rem;
    display: flex;
    flex-wrap: wrap;
    margin-top: 0.35rem;
    row-gap: 0.5rem;
}

/* The channels the offer card does not spell out keep their glyph and nothing else, in a row under
   the card's corner buttons. They join the button column rather than standing on their own so the
   whole right-hand block reads as one group, and they wrap to a second row instead of pushing the
   buttons narrower. The links take no colour of their own: they are the same anchors as the rows
   below, and the glyph draws in currentColor. */
.listing-data-seller-icon-links {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    justify-content: flex-end;
}

/* The glyph is the whole target, so the box is grown to a finger-sized one around it -- an 18px
   icon on its own is a tap the thumb misses. */
.listing-data-seller-icon-link {
    align-items: center;
    border-radius: 6px;
    display: inline-flex;
    justify-content: center;
    min-height: 28px;
    min-width: 28px;
}

.listing-data-seller-icon-link:focus-visible {
    outline: 2px solid var(--md-primary);
    outline-offset: 2px;
}

/* Icon-led summary lines: the glyph sits on the first row only; text-indent indents line 1 past
   the icon while wrapped lines start at the full left edge.
   The name is one of these too. As an atomic inline-flex box it could not be split, so beside the
   card's floated action buttons a name too long for the narrowed line dropped below the buttons
   whole -- and took every line after it down with it. Wrapping in place keeps each value on its
   own lines: a line is only narrowed while the buttons are beside it, and the first line past
   them goes back to the card's full width on its own. The glyph cannot stay in flow for this --
   the line is allowed to break between it and the first word. */
.summary-schedule,
.summary-card-name,
.listing-data-seller-link {
    --summary-icon-size: 14px;
    --summary-icon-line-indent: calc(var(--summary-icon-size) + 0.35rem);
    display: block;
    min-width: 0;
    position: relative;
    text-indent: var(--summary-icon-line-indent);
}

/* Passed to MatIcon as CssClass; the App never selects the component's own .mat-icon.
   The glyph centres on the first line box instead of sitting at its top edge: out of flow it gets
   none of the half-leading the words beside it get, so top:0 left it riding above their cap height.
   1lh is the line's own height, so the one rule serves every line here -- the 0.8rem subtext line
   and the taller name line each centre against their own leading, no per-line nudge. */
.summary-line-icon,
.summary-name-icon {
    left: 0;
    position: absolute;
    top: 0.15em; /* Browsers without the lh unit: half-leading of a normal Roboto line. */
    top: calc((1lh - var(--summary-icon-size)) / 2);
}

/* Only a value too long for a whole row breaks -- a profile URL or an address -- and it breaks
   rather than pushing the card wider than the sheet. Everything shorter stays on one line. */
.listing-data-seller-link {
    overflow-wrap: break-word;
}

/* Without a photo there is no thumbnail column either — the track would otherwise hold 88px of
   nothing and push the text off the card's left edge. */
.listing-data-product-card .summary-card-product-body:not(:has(.summary-card-photo-thumbnail-button)) {
    grid-template-columns: minmax(0, 1fr);
}

.listing-data-product-card .summary-card-product-body:not(:has(.summary-card-photo-thumbnail-button)) .summary-card-product-facts {
    grid-column: 1;
}

/* The enlarged photo covers the sheet instead of growing inside it, so the card behind it
   keeps its layout. Its width matches the sheet content area (sheet width minus the sheet padding),
   and a click anywhere on the overlay closes it. */
.listing-data-photo-overlay {
    align-items: center;
    background: rgba(0, 0, 0, 0.72);
    border: 0;
    cursor: zoom-out;
    display: flex;
    inset: 0;
    justify-content: center;
    padding: 1.25rem;
    position: fixed;
    z-index: 60;
}

.listing-data-photo-overlay img,
.listing-data-photo-overlay svg {
    border-radius: 12px;
    display: block;
    max-height: 100%;
    max-width: min(100%, 26.3rem);
    object-fit: contain;
}

/* Seller and listing link cards share the compact QR layout and enlarged overlay. */

/* Black on white in both themes and with its own quiet-zone margin baked into the viewBox — a code
   tinted to the surface, or butted against the sheet edge, stops scanning. */
.listing-qr-code {
    background: #ffffff;
    border-radius: 12px;
    display: block;
    height: auto;
    max-width: 100%;
    width: 16rem;
}

/* Centred under the enlarged code, but in the seller card's content column it sits below the
   buttons row and takes the column's full width, left-aligned on its own line. */
.summary-card-photo-content > .listing-qr-url {
    text-align: left;
}

/* Enlarged over the sheet the code takes the overlay's full content width, not the 16rem it uses
   inline. .listing-data-photo-overlay svg caps it at the sheet content width. */
.listing-qr-code-enlarged {
    width: 100%;
}

.listing-qr-url {
    color: var(--md-on-surface-variant);
    font-size: 0.8125rem;
    margin: 0;
    overflow-wrap: anywhere;
    text-align: center;
}

/* The email is shown as a message card, separate from the editable delivery headers above it. */
.listing-email-share-form {
    display: grid;
    gap: 0.5rem;
}

.listing-email-preview {
    display: grid;
    gap: 0;
}

.listing-email-preview > .summary-field-label {
    margin-left: 0.7rem;
}

.listing-email-preview-message {
    border: 1px solid var(--input-border);
    border-radius: 8px;
    color: var(--md-on-surface);
    font-size: 0.875rem;
    line-height: 1.4;
    padding: 0.85rem;
}

.listing-email-preview-message p {
    margin: 0 0 0.85rem;
}

.listing-email-preview-message p:last-child {
    margin-bottom: 0;
}

.listing-email-preview-photo {
    border-radius: 6px;
    display: block;
    height: auto;
    margin-bottom: 0.85rem;
    max-width: 100%;
}

.listing-email-preview-link {
    color: var(--md-primary);
    text-decoration: underline;
}

.detail-action-message {
    color: var(--md-on-surface-variant);
    font-size: 0.875rem;
    margin: -0.25rem 0 0;
}

.interaction-panel {
    border-top: 1px solid #e0e7e2;
    display: grid;
    gap: 0.5rem;
    padding-top: 0.85rem;
}

/* Rating panel mirrors the listing cards: title-to-label matches the sheet header gap, label-to-
   stars matches label-to-card (summary-card-section gap 0), and stars-to-Kommentaar matches the
   gap between one card and the next section label. Gaps are measured from the star row itself. */
.interaction-panel-rating {
    gap: calc(1rem - 5px);
}

.interaction-panel-rating > .interaction-header {
    margin-bottom: calc(3px - (1rem - 5px));
}

.interaction-header {
    align-items: center;
    display: flex;
    gap: 1rem;
    justify-content: space-between;
}

.interaction-header h3 {
    font-size: 1rem;
    margin: 0;
}

.interaction-input,
.interaction-textarea {
    background: #ffffff;
    border: 1px solid var(--input-border);
    border-radius: 6px;
    color: var(--text-body);
    font: inherit;
    min-height: 2.25rem;
    padding: 0.55rem 0.65rem;
}

.interaction-textarea {
    min-height: 4.5rem;
    resize: vertical;
}

.group-offer-button {
    background: #fff;
    border: 1px solid #d6ddd7;
    border-radius: 8px;
    color: #16231f;
    cursor: pointer;
    display: grid;
    gap: 0.2rem;
    padding: 0.75rem;
    text-align: left;
}

.group-offer-button span {
    color: var(--eyebrow);
    font-size: 0.875rem;
}

.group-offer-button:hover,
.group-offer-button:focus-visible {
    border-color: #1f6f5b;
    outline: none;
}

.seller-page {
    display: grid;
    font-family: inherit;
    gap: 1rem;
}

.seller-form {
    display: grid;
    gap: 1rem;
}

.form-section {
    display: grid;
    gap: 0.5rem;
}

/* A grid item's automatic minimum size is its min-content width, so one row that cannot shrink
   widens the whole track -- and then every other row, stretched to that track, overflows the sheet
   together. The rows that pair two fields (.offer-time-row) size those fields from a percentage
   flex-basis, which makes the row's min-content the sum of the two inputs' intrinsic 20-character
   widths (~550px), far past any phone. The fields themselves already carry min-width: 0 and shrink
   correctly once the track stops being inflated. */
.form-section > * {
    min-width: 0;
}

.form-section h2 {
    font-size: 1rem;
    font-weight: 500;
    margin: 0;
    text-transform: none;
}

.seller-page .detail-eyebrow {
    font-weight: 500;
    text-transform: none;
}

.seller-page .section-hint {
    color: var(--text-muted);
    font-size: 0.75rem;
    font-weight: 400;
    line-height: 1.4;
    margin: -0.2rem 0 0.75rem;
    text-transform: none;
}

.seller-page .form-grid label,
.seller-page .form-section > label {
    font-size: 0.875rem;
    font-weight: 500;
    text-transform: none;
}

.form-grid {
    display: grid;
    gap: 0.75rem;
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.form-grid label,
.form-section > label,
.interaction-panel label {
    color: var(--text-muted);
    display: grid;
    font-size: 0.78rem;
    font-weight: 700;
    gap: 0.3rem;
    text-transform: none;
}

.terms-confirmation-control {
    grid-column: 1 / -1;
}

.form-grid input,
.form-grid select,
.form-section input[type="date"],
.form-section input[type="time"] {
    background: #ffffff;
    border: 1px solid var(--input-border);
    border-radius: 6px;
    color: var(--text-body);
    font: inherit;
    min-height: 2.35rem;
    padding: 0 0.65rem;
    text-transform: none;
}

.form-section input[type="time"].time-input-24h::-webkit-datetime-edit-ampm-field {
    display: none;
}

.form-section input[type="time"].time-input-24h::-webkit-calendar-picker-indicator {
    filter: none;
}

.form-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    justify-content: flex-end;
}

.message-feedback-link {
    font-size: 14px;
    margin: 1.25rem 0 0;
}



/* .form-section and .form-section > label inside these panels are covered by the
   global .form-section / .form-section > label rules; only the width/margin tweaks
   below are panel-specific. */
.spot-data-panel .interaction-input,
.product-data-panel .interaction-input,
.offer-main-panel .interaction-input,
.image-data-panel .interaction-input {
    box-sizing: border-box;
    display: block;
    width: 100%;
}

.spot-data-panel .interaction-textarea,
.product-data-panel .interaction-textarea,
.offer-main-panel .interaction-textarea,
.image-data-panel .interaction-textarea {
    box-sizing: border-box;
    display: block;
    min-height: 5rem;
    width: 100%;
}

.summary-card {
    background: #f8f9fa;
    border: 1px solid var(--input-border);
    border-radius: 8px;
    padding: 0.75rem;
}

/* Same 1.1rem label lane as AppFloatField.label-above-field / .float-field-lane. */
.summary-field-label {
    align-items: center;
    color: var(--md-primary);
    display: inline-flex;
    gap: 0.35rem;
    font-size: var(--app-font-size-label);
    line-height: 1.1rem;
    pointer-events: none;
}

.field-required-dot {
    background-color: var(--error-text);
    border-radius: 50%;
    display: inline-block;
    flex-shrink: 0;
    height: 6px;
    width: 6px;
}

.summary-card-section {
    display: grid;
    gap: 0;
}

.summary-card-section > .summary-field-label {
    margin-left: 0.75rem;
}

.summary-card-actions {
    align-items: center;
    display: flex;
    flex-shrink: 0;
    flex-wrap: wrap;
    gap: 0.35rem;
    justify-content: flex-end;
}

/* Actions hug the card's top-right corner and the summary content flows around them, so short
   facts sit beside the buttons instead of below an empty action row. They stack one per line
   against the card's right edge rather than sharing a row: the labels are full words of varying
   length, so a row of them reads as a ragged block and is the first thing to overflow a narrow
   card. Declared after .summary-card-actions because the two carry equal specificity and this
   has to win the row/column choice. */
.summary-card-corner-actions {
    align-items: flex-end;
    display: flex;
    flex-direction: column;
    float: right;
    gap: 0.35rem;
    margin: 0 0 0.35rem 0.75rem;
    max-width: 100%;
    position: relative;
    z-index: 1;
}

.summary-card-product-row {
    margin-top: 0.35rem;
}

.summary-card-product-body {
    align-items: flex-start;
    display: grid;
    gap: 0.75rem;
    grid-template-columns: 88px minmax(0, 1fr);
    min-width: 0;
}

.summary-card-product-facts {
    display: flow-root;
    grid-column: 2;
    min-width: 0;
}

/* Placement of the quantity field in the product card. These are the classes the sheet passes to
   AppFloatField (WrapperClass), so they land on the field's frame and never touch its look:
   collapsed it is the "Kogus" button at its own width, expanded it takes 45% of the row. */
.summary-card-product-body .summary-card-product-quantity-field {
    clear: right;
    float: right;
    margin: 0 0 0.35rem 0.75rem;
}

.summary-card-product-body .summary-card-product-quantity-field.is-expanded {
    box-sizing: border-box;
    max-width: 100%;
    min-width: 6.5rem;
    width: 45%;
}

.summary-card-image-description {
    margin-top: 0.35rem;
}

.summary-card > .summary-card-actions {
    margin-top: 0.35rem;
}

.summary-card > *:first-child {
    margin-top: 0;
}

/* Selection state: photo placeholder/thumbnail on the left, the "previously used" select and its
   actions stacked beside it so the card stays one row tall. */
.summary-card-select-row {
    align-items: flex-start;
    display: flex;
    gap: 0.75rem;
    margin-top: 0.35rem;
    min-width: 0;
}

.summary-card-select-column {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 0.35rem;
    min-width: 0;
    --app-float-field-width: 100%;
}

.summary-card-select-column .summary-card-actions {
    margin-top: 0;
}

.summary-card-body {
    display: flow-root;
    margin-top: 0.35rem;
    min-width: 0;
}

.summary-card-body:first-child {
    margin-top: 0;
}

.summary-subtext {
    color: var(--text-muted);
    display: block;
    font-size: 0.8rem;
}

/* The offers a Kuulutused card names under its count line. The numbers are the list's own markers,
   and the indent is what keeps a wrapped caption clear of them. */
.info-card-offer-list {
    color: var(--text-muted);
    font-size: 0.8rem;
    margin: 0.35rem 0 0;
    padding-left: 1.4rem;
}

.info-card-offer-list li {
    margin-top: 0.15rem;
}

.info-card-offer-list li:first-child {
    margin-top: 0;
}

/* The payment glyphs sit tight together as one group, and the names that follow keep a wider gap so
   the row reads as icons-then-list rather than one icon per name. */
.listing-data-payment-row {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: 0.15rem;
}

.listing-data-payment-row > span {
    margin-left: 0.35rem;
}

.image-capture-actions {
    display: flex;
    gap: 0.6rem;
}

.image-capture-actions .secondary-command {
    align-items: center;
    display: inline-flex;
    flex: 1;
    gap: 0.35rem;
    justify-content: center;
}

.uploaded-image-thumb {
    border-radius: 8px;
    display: block;
    height: 88px;
    object-fit: cover;
    width: 88px;
}

/* SVG QR thumbnails use the same 88x88 box as image thumbnails. object-fit does not apply to
   inline SVG, so the viewBox handles scaling and the background keeps the quiet zone white. */
svg.uploaded-image-thumb {
    background: #ffffff;
    object-fit: fill;
}

.summary-card-photo-thumbnail-button {
    background: transparent;
    border: 0;
    border-radius: 8px;
    cursor: pointer;
    display: block;
    flex: 0 0 88px;
    line-height: 0;
    overflow: hidden;
    padding: 0;
    position: relative;
    transition: box-shadow 0.15s ease;
}

.summary-card-photo-thumbnail-button:hover,
.summary-card-photo-thumbnail-button:focus-visible {
    box-shadow: inset 0 0 0 2px var(--md-primary);
    outline: none;
}

.summary-card-photo-thumbnail-button:hover .uploaded-image-thumb,
.summary-card-photo-thumbnail-button:focus-visible .uploaded-image-thumb {
    filter: brightness(0.82);
}

/* The seller card's code is the only thumbnail that is not a photo: it carries its own white edge in
   the viewBox, so it needs less room around it. It gives back 10% of the 88px box and takes half the
   card padding and half the row gap as its frame -- the buttons and the link beside it keep the
   card's normal spacing. */
.share-qr-thumbnail-button {
    align-self: flex-end;
    flex: 0 0 4.25rem;
    margin: -0.375rem;
}

.share-qr-thumb {
    height: 4.25rem;
    width: 4.25rem;
}

.summary-card-photo-placeholder {
    align-items: center;
    background: var(--primary-tint);
    border: 0;
    border-radius: 8px;
    color: var(--md-primary);
    cursor: pointer;
    display: inline-flex;
    flex: 0 0 88px;
    height: 88px;
    justify-content: center;
    padding: 0;
    position: relative;
    transition: background 0.15s ease, box-shadow 0.15s ease;
    width: 88px;
}

/* Small add mark in the placeholder's top-right corner; the camera glyph stays centered. */
.photo-placeholder-plus {
    display: inline-flex;
    position: absolute;
    right: 4px;
    top: 4px;
}

/* Small edit mark in the thumbnail's top-right corner when an image is set. */
.photo-thumbnail-edit {
    color: #ffffff;
    display: inline-flex;
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.8));
    position: absolute;
    right: 4px;
    top: 4px;
}

.summary-card-photo-placeholder:hover,
.summary-card-photo-placeholder:focus-visible {
    background: rgba(65, 95, 145, 0.16);
    box-shadow: inset 0 0 0 2px var(--md-primary);
    color: var(--md-primary);
    outline: none;
}

.summary-image-preview {
    align-items: center;
    display: flex;
    float: left;
    gap: 0.75rem;
    margin: 0 0.75rem 0.2rem 0;
}

.summary-card-photo {
    align-items: flex-start;
    display: flex;
    gap: 0.75rem;
    margin-top: 0.35rem;
}

.summary-card-photo-content {
    display: flow-root;
    flex: 1;
    min-width: 0;
}

/* The buttons sit on one line at the top of the content column, aligned to its right edge; the
   share URL takes the column's full width below them, bottom-aligned with the foot of the code
   beside it. Stacking the buttons vertically in a side column stole width from the URL and wrapped
   it mid-path; one row of buttons above a full-width URL keeps the path on one line. */
.share-qr-link-content {
    align-self: stretch;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    margin-bottom: -0.375rem;
}

.share-qr-link-content > .summary-card-corner-actions {
    flex-direction: row;
    float: none;
    justify-content: flex-end;
    margin: 0;
}

.share-qr-link-content > .listing-qr-url {
    clear: none;
    margin-top: auto;
}

.summary-card-photo-note {
    color: var(--text-muted);
    display: block;
    font-size: 0.85rem;
    line-height: 1.35;
    margin-top: 0;
    white-space: pre-wrap;
    word-break: break-word;
}

.summary-card-photo-content > .summary-card-photo-note:not(:first-child),
.summary-card-photo-content > .summary-subtext + .summary-card-photo-note {
    margin-top: 0.25rem;
}

.field-label-row {
    align-items: baseline;
    display: flex;
    gap: 0.5rem;
    justify-content: space-between;
}

.field-label-action.text-command {
    font-size: inherit;
    min-height: auto;
    padding: 0 0.25rem;
}

.offer-optional-actions-row {
    align-items: flex-end;
    display: flex;
    flex-wrap: nowrap;
    gap: 0.5rem;
    --app-float-field-flex: 1 1 0;
    --app-float-field-min-width: 0;
    --app-float-field-width: 100%;
}

.offer-time-row {
    display: flex;
    gap: 0.5rem;
    --app-float-field-flex: 0 0 calc(50% - 0.25rem);
    --app-float-field-max-width: calc(50% - 0.25rem);
    --app-float-field-min-width: 0;
    --app-float-field-width: 100%;
}

.offer-description-row {
    display: flex;
    justify-content: stretch;
    --app-float-field-flex: 1 1 100%;
    --app-float-field-max-width: 100%;
    --app-float-field-width: 100%;
}

.offer-limited-amount-row {
    display: flex;
    justify-content: flex-start;
    --app-float-field-min-width: 0;
}

/* The notice fills the row; the button that replaces it keeps its own compact width. */
.offer-limited-amount-row.is-notice {
    --app-float-field-flex: 1 1 100%;
    --app-float-field-max-width: 100%;
    --app-float-field-width: 100%;
}

/* Layout slot for the date fields' day-step and the time fields' hour-step buttons; the buttons own
   their own size. The negative end margin buys back part of the field's own padding, which the two
   date fields need when they share one row. */
.offer-date-step,
.offer-time-step {
    align-items: center;
    display: inline-flex;
    flex: 0 0 auto;
    margin-inline-end: -0.45rem;
    margin-inline-start: auto;
}

/* Keep the date-step controls in fixed slots when restoring the start date would do nothing. */
.offer-date-clear-placeholder {
    block-size: 24px;
    display: inline-block;
    inline-size: 24px;
}

.offer-date-fields.is-period {
    display: grid;
    gap: 0.75rem;
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.offer-date-fields.is-period > label {
    min-width: 0;
}


.auth-panel .auth-form {
    max-width: none;
}

.location-permission-panel .app-command,
.logout-panel .app-command,
.verify-email-panel .app-command {
    align-items: center;
    display: inline-flex;
    gap: 0.5rem;
}

.about-panel-map-attribution {
    color: var(--text-secondary);
    font-size: 0.875rem;
    line-height: 1.5;
    margin: 1rem 0 0;
}

.about-panel-funding {
    margin-top: 1.5rem;
    padding-top: 1.25rem;
}

.about-panel-funding-logo-strip {
    background: #fff;
    display: flex;
    justify-content: center;
    margin: 0 0 1rem;
}

.about-panel-funding-logo {
    display: block;
    height: auto;
    max-width: min(100%, 396px);
}

.about-panel-funding-info {
    color: var(--text-secondary);
    font-size: 0.875rem;
    line-height: 1.5;
    margin: 0;
}

/* Uudised is the listings overlay with articles in it: the same .listing-panel scroller and the
   same .listing-list card column over a stationary map. It is positioned against the viewport
   rather than carried inside .map-list-track, because that track slides between exactly two panels
   -- the map and the listing list -- and Uudised covers whichever of them is showing. Transparent,
   and transparent to the pointer, so only the cards themselves take the map's place; the tail slack
   and hidden scrollbar come with .listing-panel ([[uc_app_public_news]]).
   z-index 55: above the sheet scrim (40) and panel (50), under the account menu (60). The
   favourites track's will-change/transform would trap that z-index; drop the trap while this
   column is open (favourites is already closed by home-panel exclusion). */
.slide-viewport > .news-panel {
    background: transparent;
    inset: 0;
    pointer-events: none;
    position: absolute;
    z-index: 55;
}

.app-shell:has(.news-panel) .favourites-slide-track {
    transform: none;
    will-change: auto;
}

.app-shell:has(.news-panel) .favourites-slide-track > .favourites-side-panel {
    display: none;
}

.news-panel > .listing-list {
    pointer-events: none;
}

.news-panel > .listing-list > * {
    pointer-events: auto;
    /* pan-y: the browser keeps owning the vertical pan that scrolls the column, while a
       horizontal drag on a card is left to the swipe-away binding in bottom_sheet.js --
       claimed natively it would die on pointercancel a few pixels in
       ([[uc_app_public_news]]). */
    touch-action: pan-y;
}

/* Runway past the last article rather than up to it. The listing tail deliberately stops one tile
   short, so its last tile stays on screen at full scroll — here the reader scrolls the column clear
   of the map and the overlay closes itself, which that tail would make unreachable: it leaves about
   a tile's height showing, more than the threshold the close waits for. A full panel height of slack
   lets the last card leave the viewport, and the close animates the remainder
   ([[uc_app_public_news]]). */
.news-panel > .listing-list::after {
    height: 100cqh;
}

/* The article card is the listing tile's surface with an article in it, so Uudised and the home
   listing overlay read as one column. A flex column so the leading picture stretches to the card's
   full width on its own: with the negative margins below, stretch is what makes it bleed past the
   padding on both sides without the card having to restate its own width anywhere. */
.news-article {
    background: var(--app-listing-surface);
    border-radius: 0.75rem;
    box-shadow: 0 1px 3px var(--app-listing-shadow);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding: 0.75rem;
}

/* The picture leads the card, spanning it corner to corner: negative margins of exactly the card's
   own padding, with the card's overflow clipping it to the rounded corners. It has no fixed height
   -- a news picture is editorial, so it keeps its aspect ratio rather than being cropped to a box
   the way a listing thumbnail is. White behind it, because the pictures that come with an article
   are often logos drawn for a white page. The rule is on the image itself, so a card whose picture
   fails to load has no band at all rather than an empty strip. */
.news-article-image {
    background: #fff;
    display: block;
    height: auto;
    margin: -0.75rem -0.75rem 6px;
}

.news-article-title {
    color: var(--md-on-surface);
    font-size: 0.9rem;
    font-weight: 700;
    line-height: 1.2;
    margin: 0;
}

.news-article-date {
    color: var(--md-on-surface-variant);
    font-size: var(--app-font-size-label);
    margin: 0.125rem 0 0;
}

/* A blank line in the authored text is a paragraph break: the text is split into one p per
   paragraph, and the gap between them is half an empty line (0.75em against the 1.5 line-height)
   rather than the whole empty line the raw breaks would render. A single line break inside a
   paragraph is part of the text too, so each p keeps it through pre-line. */
.news-article-text {
    font-size: 0.875rem;
    line-height: 1.5;
    margin-top: 0.25rem;
}

.news-article-text p {
    margin: 0 0 0.75em;
    white-space: pre-line;
}

.news-article-text p:last-child {
    margin-bottom: 0;
}

/* The card's command row: Loe edasi, then Ava when the article points somewhere. It hugs its own
   commands instead of stretching across the flex column, so a hover tint covers the command and not
   the card. */
.news-article-commands {
    align-items: center;
    align-self: flex-start;
    display: flex;
    gap: 0.25rem;
    margin-top: 0.25rem;
}

/* Both are .text-command; only their place in the card belongs here. The first one drops its start
   padding so the label lines up with the article text above it, and Ava — a link, not a button —
   drops the underline so the two read as one pair. */
.news-article-command {
    text-decoration: none;
}

.news-article-commands > .news-article-command:first-child {
    padding-inline-start: 0;
}

/* Loading and empty-state lines stand directly on the map once the cards are gone, so they take the
   card surface rather than sitting as bare text over the tiles. */
.news-status {
    background: var(--app-listing-surface);
    border-radius: 0.75rem;
    box-shadow: 0 1px 3px var(--app-listing-shadow);
    color: var(--md-on-surface-variant);
    font-size: 0.875rem;
    margin: 0;
    padding: 0.75rem;
}

.privacy-panel-body {
    font-size: 0.875rem;
    line-height: 1.5;
    white-space: pre-line;
}

.privacy-panel-body p {
    margin: 0 0 0.625rem;
}

.privacy-panel-body p:last-child {
    margin-bottom: 0;
}

.terms-panel-version {
    color: var(--md-on-surface-variant);
    margin-top: 1rem;
}



.auth-form {
    display: grid;
    gap: 0.5rem;
    max-width: 26rem;
}

/* Compact seller-data layout. AppFloatField owns every field's input, button presentation, and
   above-the-field label lane (1.1rem on expanded inputs only; permanent button actions and
   collapsed-empty buttons skip it). The grid gap is only between field frames (0.5rem). */
.seller-compact {
    display: grid;
    gap: 0.5rem;
}

/* Compact style: optional three-field groups share one row while all members are still empty. */
.seller-social-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

/* Row placement only: how the three buttons share the row. Centring their content is the field's
   own CenterButtonContent, not a padding tweak from here. */
.seller-social-action {
    align-self: stretch;
    flex: 1 1 0;
    min-width: 0;
}

/* Compact-style open field: an outlined box whose label rides from the vertical centre up onto the
   top border line on focus / when filled — the same motion as the "Otsi pakkumisi" search field. */
.seller-float-field {
    align-items: center;
    border: 1px solid var(--md-outline);
    border-radius: 0.875rem;
    display: flex;
    gap: 0.5rem;
    min-height: 2.75rem;
    padding: 0 0.85rem;
    position: relative;
}

/* Leading field icon (matches the collapsed button's icon) and the read-only domain prefix for the
   Facebook / Instagram fields. Both sit beside the input, which keeps flex:1, so the editable area
   never covers them. */
.seller-float-icon {
    color: var(--md-on-surface-variant);
}

.seller-float-prefix {
    color: var(--md-on-surface-variant);
    flex: 0 0 auto;
    pointer-events: none;
    white-space: nowrap;
}

.seller-float-field:focus-within {
    border-color: var(--md-primary);
    box-shadow: inset 0 0 0 1px var(--md-primary);
}

.seller-compact-style-two .seller-float-field:focus-within {
    background: #fff;
}

.seller-float-field input {
    background: transparent;
    border: 0;
    color: var(--md-on-surface);
    flex: 1;
    font: inherit;
    min-width: 0;
    outline: none;
}

/* The offer editor uses the same compact floating-label treatment as the user-data sheets, while
   retaining its multiline description field. */
.offer-main-panel .offer-float-field {
    background: #fff;
}

.spot-data-panel .spot-name-field {
    background: #fff;
}

.product-data-panel .product-float-field {
    background: #fff;
}

.image-data-panel .image-comment-field {
    align-items: stretch;
    background: #fff;
    min-height: 6rem;
}

.image-data-panel .image-comment-field textarea {
    background: transparent;
    border: 0;
    color: var(--md-on-surface);
    flex: 1;
    font: inherit;
    min-width: 0;
    outline: none;
    padding: 0.7rem 0;
    resize: vertical;
}

.image-data-panel .image-comment-field .seller-float-label {
    top: 1.35rem;
}

.image-data-panel .image-comment-field:focus-within .seller-float-label {
    top: 0;
}

.product-definition-price-row {
    display: grid;
    gap: 0.5rem;
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.offer-main-panel .offer-float-field textarea {
    background: transparent;
    border: 0;
    color: var(--md-on-surface);
    flex: 1;
    font: inherit;
    min-width: 0;
    outline: none;
    padding: 0.7rem 0;
    resize: vertical;
}

.offer-main-panel .offer-float-textarea {
    align-items: stretch;
    min-height: 6rem;
}

.offer-main-panel .offer-float-textarea .seller-float-label {
    top: 1.35rem;
}

.offer-main-panel .offer-float-textarea:focus-within .seller-float-label {
    top: 0;
}

.seller-float-label {
    color: var(--md-on-surface-variant);
    left: 0.85rem;
    pointer-events: none;
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    transition: all 0.15s ease;
}

.seller-float-field:focus-within .seller-float-label {
    background: var(--sheet-bg);
    font-size: 0.75rem;
    left: 0.7rem;
    padding: 0 0.25rem;
    top: 0;
}

.seller-float-field:focus-within .seller-float-label {
    color: var(--md-primary);
}

.seller-compact-style-two .seller-float-field:focus-within .seller-float-label {
    background: #fff;
}

.seller-compact-company {
    display: grid;
    gap: 0.5rem;
}

.seller-compact-style {
    background: transparent;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    font: inherit;
    justify-self: start;
    padding: 0.2rem 0.1rem;
    text-decoration: underline;
}

.seller-compact-style:hover,
.seller-compact-style:focus-visible {
    color: var(--md-primary);
    outline: none;
}

/* Brand provider glyph (e.g. Google) inside an auth button. */
.auth-provider-icon {
    display: block;
    flex-shrink: 0;
    height: 18px;
    width: 18px;
}

.app-loading {
    background: #e5f0eb;
    border-radius: 6px;
    color: #21483f;
    margin-bottom: 1rem;
    padding: 0.75rem 1rem;
}

#blazor-error-ui {
    background: #fae7e6;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.75rem 3rem 0.75rem 1rem;
    position: fixed;
    right: 0;
    z-index: 1000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 1rem;
}

/* Flutter mobile breakpoint (_kMobileBreakpoint = 600): the role selector,
   date chip and filter/view buttons move to a bottom control bar. */
@media (max-width: 600px) {
    /* The narrow bar is the control strip alone -- no heading to give it presence -- so it carries
       less air than the wide one. Measured to the ink: the tallest thing in the strip is a 1.75rem
       pill, leaving 30px of whitespace at the shared 58px; keeping 70% of that puts the bar at
       49px. Redefining the token rather than the bar's own height keeps the sheet offsets below,
       which subtract it, in step. The wide bar is display:none here, so it stays at 58px. */
    :root {
        --app-top-bar-height: 49px;
    }

    /* Plain elements only. AppUi components own their own display, so AppTooltip and MatIcon
       honour these two classes in their own scoped CSS instead of being overridden from here. */
    .hide-mobile {
        display: none;
    }

    main.main-page {
        padding: 0.5rem;
    }

    /* Bottom sheets slide up above the pinned toolbar; scrim dims only the area above it. */
    .app-shell:has(.app-top-bar--bottom) .sheet-scrim {
        bottom: var(--app-top-bar-height);
    }

    .app-shell:has(.app-top-bar--bottom) .bottom-sheet {
        bottom: var(--app-top-bar-height);
        max-height: calc(100dvh - var(--app-top-bar-height));
    }

    .role-segment-button {
        padding: 0 0.375rem;
    }

    .listing-panel {
        padding: 0.75rem 0.75rem 6rem;
    }

    .form-grid {
        grid-template-columns: 1fr;
    }

    .form-actions {
        justify-content: flex-start;
    }

}

@media (min-width: 601px) {
    .show-mobile {
        display: none;
    }

}

/* App tooltips are owned by the AppTooltip component (Fishy26.AppUi); the Primer
   .tooltipped bubble styling that used to live here has moved into that control. */
