@import url('https://fonts.googleapis.com/css2?family=Assistant:wght@200..800&family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap');
    .poi-action-icons.svelte-10larau {
      display: flex;
      flex-direction: column;
      gap: 4px;
      padding: 8px 0;
      width: 100%;
      box-sizing: border-box;
    }

    .action-row.svelte-10larau {
      display: flex;
      flex-direction: row;
      align-items: center;
      gap: 12px;
      padding: 4px 12px;
      background-color: transparent;
      color: var(--color-text);
      cursor: pointer;
      transition: background-color 0.2s ease-in-out;
      border: 0;
      margin: 0;
      text-align: left;
      width: 100%;
    }

    .action-row.svelte-10larau:hover {
      background-color: var(--color-background-mute);
    }

    .icon-wrapper.svelte-10larau {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 32px;
      height: 32px;
      flex-shrink: 0;
    }

    .action-title.svelte-10larau {
      font-size: 14px;
      color: var(--color-indigo-600);
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;

      &:hover {
        text-decoration: underline;
      }
    }

    .action-row.svelte-10larau .logo:where(.svelte-10larau) {
      width: 32px;
      height: 32px;
      background-size: contain;
      background-repeat: no-repeat;
      background-position: center;
    }

    .action-row.youtube.svelte-10larau .logo:where(.svelte-10larau) {
      background-image: url('../../../map-graphics/youtube.png');
      background-size: 28px;
    }

    .action-row.navily.svelte-10larau .logo:where(.svelte-10larau) {
      background-image: url('../../../map-graphics/navily.png');
      background-size: 160px;
      background-position: -14px -6px;
    }

    .action-row.google-maps.svelte-10larau .logo:where(.svelte-10larau) {
      background-image: url('../../../map-graphics/maps.png');
      background-size: 58px;
    }

    .action-row.external.svelte-10larau .logo:where(.svelte-10larau) {
      background-image: url('../../../map-graphics/external.png');
      background-size: 22px;
    }

    @media (max-width: 600px) {
    }

    /* Dark mode (class-based — html.dark) */
    html.dark .action-row.svelte-10larau {
      color: #f3f4f6;
    }
    html.dark .action-row.svelte-10larau:hover {
      background-color: #374151;
    }
    html.dark .action-title.svelte-10larau {
      color: #93c5fd;
    }
    /* The external-link logo is a single-colour black PNG that vanishes on
       the dark panel; invert it to white. The Navily/YouTube/Google-Maps
       logos are full-colour bitmaps and stay untouched. */
    html.dark .action-row.external.svelte-10larau .logo:where(.svelte-10larau) {
      filter: invert(1);
    }


  .button-container.svelte-6v9ve9 {
    display: flex;
    justify-content: center;
    width: 100%;
    margin: 8px 0;
  }

  .google-place-button.svelte-6v9ve9 {
    display: inline-flex;
    flex-direction: row;
    align-items: center;
    gap: 8px;
    padding: 10px 16px;
    background-color: #e8f0fe;
    color: #1a73e8;
    border: none;
    border-radius: 20px;
    cursor: pointer;
    font-family: 'Google Sans', Roboto, Arial, sans-serif;
    font-size: 14px;
    font-weight: 400;
    transition: background-color 0.2s ease-in-out;
  }

  .google-place-button.svelte-6v9ve9:hover {
    background-color: #d2e3fc;
  }

  .google-place-button.svelte-6v9ve9:active {
    background-color: #c4d7f5;
  }

  .google-maps-logo.svelte-6v9ve9 {
    width: 20px;
    height: 20px;
    background-image: url('../../../map-graphics/maps.png');
    background-size: 52px;
    background-repeat: no-repeat;
    background-position: center;
    flex-shrink: 0;
  }

  .button-text.svelte-6v9ve9 {
    white-space: nowrap;
  }

  .button-text.svelte-6v9ve9 strong:where(.svelte-6v9ve9) {
    font-weight: 600;
  }

  /* Class-based dark mode toggled by $lib/utils/theme.ts on <html class="dark">. */
  html.dark .google-place-button.svelte-6v9ve9 {
    background-color: #1e3a8a;
    color: #93c5fd;
  }
  html.dark .google-place-button.svelte-6v9ve9:hover {
    background-color: #1e40af;
  }
  html.dark .google-place-button.svelte-6v9ve9:active {
    background-color: #2563eb;
  }


  /* 1h/3h/6h/12h/1d forecast cadence toggle (moved from PoiFacilities, U4). */
  .resolution-toggle.svelte-a42hs2 {
      display: inline-flex;
      flex-shrink: 0;
      border: 1px solid var(--color-gray-200, #e5e7eb);
      border-radius: 9999px;
      overflow: hidden;
      background: var(--card-background, #fff);
  }

  .res-btn.svelte-a42hs2 {
      border: 0;
      background: transparent;
      padding: 2px 8px;
      font-size: 12px;
      font-weight: 600;
      line-height: 1.5;
      color: #6b7280;
      cursor: pointer;
      transition: background 0.15s, color 0.15s;
  }

  .res-btn.active.svelte-a42hs2 {
      background: #1976d2;
      color: #fff;
  }

  html.dark .resolution-toggle.svelte-a42hs2 {
      border-color: #374151;
      background: #1f2937;
  }
  html.dark .res-btn.svelte-a42hs2 {
      color: #9ca3af;
  }
  html.dark .res-btn.active.svelte-a42hs2 {
      background: #60a5fa;
      color: #0b1220;
  }


  .contact-details.svelte-d5o650 {
    padding: 4px 10px;
    display: flex;
    flex-direction: column;
    row-gap: 12px;

    .contact-item:where(.svelte-d5o650) {
      display: flex;
      align-items: center;
      column-gap: 12px;
      font-size: 14px;
      color: var(--color-text);

      /* Phone/email fields: keep the original text inline with the swapped-in
         tokens, wrapping as a unit rather than stacking each on its own row. */
      .phone-field:where(.svelte-d5o650),
      .email-field:where(.svelte-d5o650) {
        display: inline-flex;
        flex-wrap: wrap;
        align-items: center;
        white-space: pre-wrap;
      }

      /* R29 — a `.contact-item a` rule used to live here, forcing every link
         in this component (email, website, tel fallback) to `#0b57d0` with
         no underline. Its selector (0,1,1) out-specifies the single-class
         `.a-normal` (0,1,0) now on those anchors, so keeping the rule
         alongside the class would have made adding the class a no-op — the
         link would still render with this rule's colour. Removed outright
         rather than merged into `a-normal`, since nothing else in this
         component's markup wants an unstyled link. */
    }
  }

  /* Dark mode (class-based — html.dark) */
  html.dark .contact-details.svelte-d5o650 .contact-item:where(.svelte-d5o650) {
    color: #f3f4f6;
  }
  html.dark .contact-details.svelte-d5o650 .material-symbols-outlined:where(.svelte-d5o650) {
    color: #d1d5db;
  }


  .haven-score-graph.svelte-1ges2s0 {
    /* Horizontal drags are the scrub; vertical ones scroll the POI pane. */
    touch-action: pan-y;
    user-select: none;
    cursor: grab;
    /* The score pill always floats above the line; at high scores it extends
       past the top of the plot frame. Let it draw there (it may overlap the
       slider above — acceptable) rather than being clipped. */
    overflow: visible;
  }

  .haven-score-graph.grabbing.svelte-1ges2s0 {
    cursor: grabbing;
  }

  .curve-layer.svelte-1ges2s0 {
    transition: transform 0.2s ease-out;
  }

  .curve-layer.dragging.svelte-1ges2s0 {
    transition: none;
  }

  /* Fill comes from the per-band alpha-ramp gradient (black); the theme strength
     is applied here as element opacity (× the gradient's 0→1→0 edge ramp). */
  .night-rect.svelte-1ges2s0 {
    opacity: 0.14;
  }

  .gridline.svelte-1ges2s0 {
    stroke: rgba(100, 116, 139, 0.35);
    stroke-width: 1;
  }

  .grid-label.svelte-1ges2s0 {
    font-size: 9px;
    font-family: sans-serif;
    fill: #64748b;
  }

  .axis-title.svelte-1ges2s0 {
    font-size: 9px;
    font-family: sans-serif;
    font-weight: 600;
    letter-spacing: 0.3px;
    fill: #94a3b8;
  }

  .marker-line.svelte-1ges2s0 {
    stroke: rgba(100, 116, 139, 0.6);
    stroke-width: 1;
    stroke-dasharray: 3 3;
  }

  .score-pill-text.svelte-1ges2s0 {
    font-size: 11px;
    font-family: sans-serif;
    font-weight: 700;
    fill: #fff;
  }

  /* Dot + pill glide vertically between steps; instant while actively scrolling
     (mirrors .curve-layer so the dot tracks the line frame-for-frame mid-drag). */
  .marker-dot.svelte-1ges2s0 {
    transition: transform 0.2s ease-out;
  }

  .marker-dot.dragging.svelte-1ges2s0 {
    transition: none;
  }

  /* Dark mode overrides */
  html.dark .night-rect.svelte-1ges2s0 {
    /* Stronger on dark so the night band stays visible against dark bands. */
    opacity: 0.30;
  }

  html.dark .gridline.svelte-1ges2s0 {
    stroke: rgba(148, 163, 184, 0.25);
  }

  html.dark .grid-label.svelte-1ges2s0 {
    fill: #94a3b8;
  }

  html.dark .axis-title.svelte-1ges2s0 {
    fill: #64748b;
  }

  html.dark .marker-line.svelte-1ges2s0 {
    stroke: rgba(148, 163, 184, 0.5);
  }


    .poi-facilities-container.svelte-1l73rip {
        width:100%;
        /* The collapse control below is `position: absolute`, and this is the
           box it must resolve against — the DETAILS section it belongs to.
           Without it the control escapes to `.poi-additional-info`, which since
           the score-explanation section was added also contains that section,
           so `top: 50%` measured half of details+explanation and floated the
           button up over the explanation's heading (in RTL it landed on top of
           the right-aligned Hebrew title). The two `top` values were always
           right; only the box they resolved against was wrong. */
        position: relative;
        display: flex;
        flex-direction: column;
        flex-wrap: wrap;
        align-items: center;
        justify-content: space-between;
        gap: 8px;
        font-size: 14px;
        color: var(--text-color);
        padding: 4px 0;
        box-sizing: border-box;
        max-height: 140px;
        overflow: hidden;

        .more:where(.svelte-1l73rip) {
            position:absolute;
            right: 12px;
            top: 50%;
            transform: translateY(-50%);
            display:flex;
            align-items: center;
            justify-content: flex-end;

            button:where(.svelte-1l73rip) {
                height: 36px;
                width: 36px;
                border:0;
                background-color: var(--color-gray-200);
                border-radius: 9999px;
                display:flex;
                align-items: center;
                justify-content: center;
                cursor: pointer;

                .material-symbols-outlined:where(.svelte-1l73rip) {
                    font-size: 24px;
                    color: var(--icon-color);
                }
            }
        }

        .poi-facilities:where(.svelte-1l73rip) {
            border:0;
            background:transparent;
            width: 100%;
            text-align: left;
            line-height: 0;
            padding-right: 40px;

            &::-webkit-scrollbar {
                display: none;
            }

            .facility-item:where(.svelte-1l73rip) {
                display: inline-flex;
                vertical-align: middle;
                align-items: center;
                gap: 4px;
                background-color: var(--card-background);
                padding: 4px 8px;
                border-radius: 4px;

                .material-symbols-outlined:where(.svelte-1l73rip) {
                    padding:2px 0;
                }

                .facility-icon:where(.svelte-1l73rip) {
                    width: 28px;
                    height: 28px;
                    min-width: 28px;
                    min-height: 28px;
                    fill: var(--icon-color);
                }
            }
        }

        &.is-open {
            max-height: none;
            align-items: flex-start;
            column-gap: 0;
            padding: 11px 3px;

            .more:where(.svelte-1l73rip) {
                top: 10px;
                transform: none;
            }

            .more-info:where(.svelte-1l73rip) {
                width:100%;
                display: flex;
                flex-direction: row;
                /* When there isn't room for the facilities beside the weather
                   section, the weather section wraps as a WHOLE onto its own
                   full-width row (its internal weather|wind-rose columns stay
                   side by side — R12: temp/humidity never above the rose). */
                flex-wrap: wrap;
                justify-content: space-between;
                align-items: flex-start;
                gap: 8px;
                /* Size container so the weather section can compress its
                   internal gap at narrow widths (see @container below). */
                container-type: inline-size;
            }

            .facilities-column:where(.svelte-1l73rip) {
                display: flex;
                flex-direction: column;
                /* basis:auto (not 0) so the column's natural width drives the
                   flex line-break: if the labels can't fit beside the weather
                   section, the weather section wraps instead of crowding them. */
                flex: 1 1 auto;
                min-width: 0;
            }

            .poi-facilities:where(.svelte-1l73rip) {
                display: flex;
                text-align: initial;
                line-height: normal;
                padding-right: 0;
                width: auto;
                flex-shrink: 0;
                flex-direction: column;
                align-items: flex-start;
                row-gap:8px;

                .facility-item:where(.svelte-1l73rip) {
                    column-gap:12px;
                }
            }

            .weather-wind-section:where(.svelte-1l73rip) {
                display: flex;
                flex-direction: row;
                /* stretch so the weather column spans the wind-rose height; that
                   lets the 1h/3h toggle (item 13) pin to the bottom, level with
                   the wind-rose legend, while the readout stays vertically centered. */
                align-items: stretch;
                gap: 35px; /* 40px to account for wind rose arrow length */
                flex-shrink: 0;
                /* Centered when it wraps onto its own row; inert while sharing
                   a row (the facilities column's flex-grow absorbs free space). */
                margin-inline: auto;
            }

            /* Narrow panels: once the weather section is on its own row and
               space is still tight, compress the inter-column gap (the weather
               column already renders above the rose arrows via z-index) —
               but NEVER stack the two columns. */
            @container (max-width: 410px) {
                .weather-wind-section:where(.svelte-1l73rip) {
                    gap: 12px;
                }
            }

            .weather-column:where(.svelte-1l73rip) {
                display: flex;
                flex-direction: column;
                align-items: center;
                justify-content: center;
                position: relative;
                z-index: 1; /* Render above wind rose arrows */
            }

            /* Wraps the WeatherDisplay so it centers in the space above the
               bottom-pinned 1h/3h toggle when the column is stretched. */
            .weather-display-wrap:where(.svelte-1l73rip) {
                flex: 1;
                display: flex;
                align-items: center;
                justify-content: center;
            }

            .wind-rose-column:where(.svelte-1l73rip) {
                flex-shrink: 0;
            }
        }
    }

    .time-slider-container.svelte-1l73rip {
        width: 100%;
    }

    /* Item 14: haven score graph (havens only) */
    .haven-graph-container.svelte-1l73rip {
        width: 100%;
        padding: 2px 0 0;
    }

    /* Worst-gust note for coarse cadences (explains a low worst-case score) */
    .max-gust-note.svelte-1l73rip {
        display: inline-flex;
        align-items: center;
        gap: 3px;
        font-size: 11px;
        font-weight: 600;
        color: #b45309; /* amber-700 */
        white-space: nowrap;
    }
    .max-gust-note.svelte-1l73rip .material-symbols-outlined:where(.svelte-1l73rip) {
        font-size: 14px;
    }
    html.dark .max-gust-note.svelte-1l73rip {
        color: #fbbf24; /* amber-400 */
    }

    /* Forecast cadence toggle styles moved to CadenceControl.svelte (U4). */

    .weather-loading.svelte-1l73rip,
    .weather-error.svelte-1l73rip {
        display: flex;
        align-items: center;
        gap: 8px;
        padding: 16px;
        color: #666;
        font-size: 13px;
    }

    .weather-error.svelte-1l73rip {
        color: #999;
    }

    .spinning.svelte-1l73rip {
        animation: svelte-1l73rip-spin 1s linear infinite;
    }

    @keyframes svelte-1l73rip-spin {
        from { transform: rotate(0deg); }
        to { transform: rotate(360deg); }
    }

    .weather-compact.svelte-1l73rip {
        display: inline-flex;
        vertical-align: middle;
        align-items: center;
        gap: 6px;
        padding: 4px 8px;
        border-radius: 4px;
        font-size: 12px;
        font-weight: 600;
    }

    .inline-windrose.svelte-1l73rip {
        display: inline-flex;
        vertical-align: middle;
    }

    .weather-compact-icon.svelte-1l73rip {
        width: 22px;
        height: 22px;
    }

    .temp-compact.svelte-1l73rip {
        color: #333;
    }

    .wind-compact.svelte-1l73rip {
        color: #1976d2;
    }

    /* Dark mode (class-based — html.dark) */
    html.dark .facility-icon.svelte-1l73rip {
        /* Facility SVGs ship as black-on-transparent — invert to white-on-
           transparent for dark mode rather than rebuilding the assets. */
        filter: invert(1);
    }
    html.dark .material-symbols-outlined.svelte-1l73rip,
    html.dark .temp-compact.svelte-1l73rip {
        color: #f3f4f6;
    }
    html.dark .wind-compact.svelte-1l73rip {
        color: #60a5fa;
    }
    html.dark .weather-compact.svelte-1l73rip .text-gray-400:where(.svelte-1l73rip) {
        color: #9ca3af;
    }
    /* Round chevron-up "collapse facilities" button uses --color-gray-200
       which the theme system doesn't remap; force a dark surface so it
       doesn't read as a flashlight on the dark panel. */
    html.dark .poi-facilities-container.svelte-1l73rip .more:where(.svelte-1l73rip) button:where(.svelte-1l73rip) {
        background-color: #374151;
    }
    html.dark .poi-facilities-container.svelte-1l73rip .more:where(.svelte-1l73rip) button:where(.svelte-1l73rip) .material-symbols-outlined:where(.svelte-1l73rip) {
        color: #f3f4f6;
    }


  .icon.share.svelte-1hj3f1v {
    border: 0;
    background: transparent;
    cursor: pointer;

    span:where(.svelte-1hj3f1v) {
      font-size: 28px;
    }
  }


  .locale-pill-wrapper.svelte-16vdizi {
    position: relative;
    display: inline-flex;
    /* RTL-safe right-align: sits at the logical end of the parent flex row
       in both LTR and RTL. */
    margin-inline-start: auto;
  }

  .locale-pill.svelte-16vdizi {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: 9999px;
    border: 1px solid rgb(0 0 0 / 12%);
    background: rgb(255 255 255 / 80%);
    color: #374151;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: 0.02em;
    cursor: pointer;
    transition: background 120ms ease, opacity 120ms ease;
  }

  .locale-pill.svelte-16vdizi:hover {
    background: rgb(255 255 255 / 100%);
  }

  .locale-pill-disabled.svelte-16vdizi {
    opacity: 0.5;
    pointer-events: none;
    cursor: wait;
  }

  .locale-pill-code.svelte-16vdizi {
    line-height: 1.2;
  }

  .locale-pill-chevron.svelte-16vdizi {
    width: 12px;
    height: 12px;
    color: rgb(0 0 0 / 50%);
  }

  .locale-pill-spinner.svelte-16vdizi {
    font-size: 12px;
    animation: svelte-16vdizi-locale-pill-spin 1s linear infinite;
  }

  @keyframes svelte-16vdizi-locale-pill-spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
  }

  .locale-pill-popover.svelte-16vdizi {
    /* FIXED, not absolute: the pill's hosts live inside SlidePanel's
       overflow-hidden box, which clips an in-panel popover on the mobile
       bottom sheet whichever direction it opens. The inline style written by
       measurePopover() carries top/left (and max-height when capped);
       placeLocalePopover keeps the RTL-aware inline-end anchoring the old
       `inset-inline-end: 0` provided. */
    position: fixed;
    z-index: 1010;
    min-width: 180px;
    padding: 4px;
    background: #fff;
    border: 1px solid rgb(0 0 0 / 8%);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgb(0 0 0 / 12%);
  }

  .locale-pill-option.svelte-16vdizi {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 6px 10px;
    border: 0;
    background: transparent;
    color: #1f2937;
    font-size: 13px;
    text-align: start;
    cursor: pointer;
    border-radius: 4px;
  }

  .locale-pill-option.svelte-16vdizi:hover,
  .locale-pill-option.svelte-16vdizi:focus-visible {
    background: rgb(0 0 0 / 5%);
    outline: none;
  }

  .locale-pill-option-active.svelte-16vdizi {
    font-weight: 600;
  }

  .locale-pill-option-check.svelte-16vdizi {
    width: 14px;
    color: #2563eb;
  }

  .locale-pill-option-name.svelte-16vdizi {
    flex: 1;
  }

  .locale-pill-option-code.svelte-16vdizi {
    color: rgb(0 0 0 / 50%);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.02em;
  }

  /* Dark mode — match the rest of the map panels. */
  html.dark .locale-pill.svelte-16vdizi {
    background: rgb(31 41 55 / 80%);
    color: #e5e7eb;
    border-color: rgb(255 255 255 / 12%);
  }

  html.dark .locale-pill.svelte-16vdizi:hover {
    background: rgb(31 41 55 / 100%);
  }

  html.dark .locale-pill-chevron.svelte-16vdizi {
    color: rgb(255 255 255 / 50%);
  }

  html.dark .locale-pill-popover.svelte-16vdizi {
    background: #1f2937;
    border-color: rgb(255 255 255 / 12%);
    color: #e5e7eb;
  }

  html.dark .locale-pill-option.svelte-16vdizi {
    color: #e5e7eb;
  }

  html.dark .locale-pill-option.svelte-16vdizi:hover,
  html.dark .locale-pill-option.svelte-16vdizi:focus-visible {
    background: rgb(255 255 255 / 10%);
  }

.report-form {
  display: flex;
  flex-direction: column;
  min-width: 0;
  height: 100%;
  overflow: hidden;
  font-family: "Open Sans", sans-serif;
}

.report-header {
  display: flex;
  gap: 8px;
  align-items: center;
  padding: 12px 16px;
  border-bottom: 1px solid #e5e7eb;

  h3 {
    flex: 1;
    margin: 0;
    font-size: 18px;
    font-weight: 600;
  }

  .back-arrow,
  .close-x {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    cursor: pointer;
    background: #f0f0f0;
    border: none;
    border-radius: 50%;
  }
}

.report-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 8px;
  padding: 16px;
  overflow-y: auto;
}

.section-label {
  margin-top: 8px;
  font-size: 14px;
  font-weight: 600;
  color: #374151;
}

/* Severity cards */
.severity-cards {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.severity-card {
  display: grid;
  grid-template-rows: auto auto;
  grid-template-columns: auto 1fr;
  column-gap: 10px;
  align-items: center;
  padding: 10px 12px;
  text-align: left;
  cursor: pointer;
  background: white;
  border: 2px solid #e5e7eb;
  border-radius: 10px;
  transition: border-color 0.15s, background-color 0.15s;

  &:hover {
    background: #f9fafb;
  }

  &.selected {
    background: color-mix(in srgb, var(--card-color) 6%, white);
    border-color: var(--card-color);
  }
}

.severity-emoji {
  grid-row: 1 / -1;
  align-self: center;
  font-size: 22px;
}

.severity-label {
  font-size: 14px;
  font-weight: 600;
  color: #1f2937;
}

.severity-sublabel {
  font-size: 12px;
  color: #6b7280;
}

/* Description textarea */
textarea#report-description {
  box-sizing: border-box;
  width: 100%;
  min-height: 80px;
  padding: 10px 12px;
  font-family: "Open Sans", sans-serif;
  font-size: 14px;
  resize: vertical;
  border: 1px solid #d1d5db;
  border-radius: 8px;

  &:focus {
    border-color: #3b82f6;
    outline: none;
    box-shadow: 0 0 0 2px rgb(59 130 246 / 20%);
  }
}

/* Photo upload */
.photo-buttons {
  display: flex;
  gap: 8px;
}

.upload-btn {
  display: inline-flex;
  gap: 6px;
  align-items: center;
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 500;
  color: #374151;
  cursor: pointer;
  background: #f3f4f6;
  border: 1px solid #d1d5db;
  border-radius: 8px;
  transition: background 0.15s;

  &:hover {
    background: #e5e7eb;
  }

  .material-symbols-outlined {
    font-size: 18px;
  }
}

.photo-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}

@media (width <= 400px) {
  .photo-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

.photo-preview {
  position: relative;
  aspect-ratio: 1;
  overflow: hidden;
  border-radius: 8px;

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

  .remove-photo {
    position: absolute;
    top: 4px;
    right: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    padding: 0;
    color: white;
    cursor: pointer;
    background: rgb(239 68 68 / 90%);
    border: none;
    border-radius: 50%;

    .material-symbols-outlined {
      font-size: 16px;
    }
  }
}

/* Email field */
.email-subtitle {
  margin: 0;
  font-size: 12px;
  color: #6b7280;
}

/* Photo upload consent notice (shown under the photo buttons in both modes) */
.photo-consent {
  margin: 6px 0 0;
  font-size: 11px;
  line-height: 1.4;
  color: #6b7280;
}

.report-form input[type="text"],
.report-form input[type="email"] {
  box-sizing: border-box;
  width: 100%;
  padding: 10px 12px;
  font-family: "Open Sans", sans-serif;
  font-size: 14px;
  border: 1px solid #d1d5db;
  border-radius: 8px;

  &:focus {
    border-color: #3b82f6;
    outline: none;
    box-shadow: 0 0 0 2px rgb(59 130 246 / 20%);
  }
}

/* Error message */
.error-message {
  margin: 0;
  font-size: 13px;
  color: #ef4444;
}

/* Submit button */
.submit-button {
  display: flex;
  gap: 8px;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: 12px 16px;
  margin-top: 8px;
  font-family: "Open Sans", sans-serif;
  font-size: 15px;
  font-weight: 600;
  color: white;
  cursor: pointer;
  background: #3b82f6;
  border: none;
  border-radius: 10px;
  transition: background 0.15s;

  &:hover:not(:disabled) {
    background: #2563eb;
  }

  &:disabled {
    cursor: not-allowed;
    background: #9ca3af;
  }

  .spinning {
    font-size: 18px;
    animation: spin 1s linear infinite;
  }
}

/* Success view */
.success-view {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  justify-content: center;
  padding: 40px 24px;
  text-align: center;

  .success-icon {
    font-size: 48px;
  }

  h3 {
    margin: 0;
    font-size: 20px;
    font-weight: 600;
    color: #1f2937;
  }

  p {
    margin: 0;
    font-size: 14px;
    color: #6b7280;
  }

  .email-note {
    font-size: 13px;
    font-style: italic;
    color: #3b82f6;
  }
}

.back-button-full {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  max-width: 240px;
  padding: 10px 20px;
  margin-top: 16px;
  font-family: "Open Sans", sans-serif;
  font-size: 14px;
  font-weight: 600;
  color: #3b82f6;
  cursor: pointer;
  background: white;
  border: 2px solid #3b82f6;
  border-radius: 10px;
  transition: background 0.15s;

  &:hover {
    background: #eff6ff;
  }
}

@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

  /* Dark mode (class-based — html.dark) lives here so :global() compiles. */
  html.dark .report-form,
  html.dark .severity-label {
    color: #f3f4f6;
  }
  html.dark .report-header {
    border-bottom-color: rgb(255 255 255 / 10%);
  }
  html.dark .report-header .back-arrow,
  html.dark .report-header .close-x {
    color: #f3f4f6;
    background: #374151;
  }
  html.dark .section-label {
    color: #e5e7eb;
  }
  html.dark .severity-card {
    color: #f3f4f6;
    background: #374151;
    border-color: #4b5563;
  }
  html.dark .severity-card:hover {
    background: #4b5563;
  }
  html.dark .severity-card.selected {
    background: color-mix(in srgb, var(--card-color) 18%, #374151);
    border-color: var(--card-color);
  }
  html.dark .severity-sublabel,
  html.dark .email-subtitle,
  html.dark .photo-consent,
  html.dark .success-view p {
    color: #9ca3af;
  }
  html.dark .report-form textarea#report-description,
  html.dark .report-form input[type="text"],
  html.dark .report-form input[type="email"] {
    color: #f3f4f6;
    background: #374151;
    border-color: #4b5563;
  }
  html.dark .report-form textarea#report-description::placeholder,
  html.dark .report-form input[type="text"]::placeholder,
  html.dark .report-form input[type="email"]::placeholder {
    color: #9ca3af;
  }
  html.dark .report-form textarea#report-description:focus,
  html.dark .report-form input[type="text"]:focus,
  html.dark .report-form input[type="email"]:focus {
    border-color: #3b82f6;
    box-shadow: 0 0 0 2px rgb(59 130 246 / 35%);
  }
  html.dark .upload-btn {
    color: #f3f4f6;
    background: #374151;
    border-color: #4b5563;
  }
  html.dark .upload-btn:hover {
    background: #4b5563;
  }
  html.dark .error-message {
    color: #f87171;
  }
  html.dark .submit-button:disabled {
    background: #4b5563;
  }
  html.dark .success-view h3 {
    color: #f3f4f6;
  }
  html.dark .success-view .email-note,
  html.dark .back-button-full {
    color: #60a5fa;
  }
  html.dark .back-button-full {
    background: transparent;
    border-color: #60a5fa;
  }
  html.dark .back-button-full:hover {
    background: rgb(96 165 250 / 12%);
  }

.slide-panel {
  overflow: hidden;
  background-color: white;
  box-shadow: 0 -2px 10px rgb(0 0 0 / 10%);
  will-change: transform;
}

.slide-panel.portrait {
  border-radius: 20px 20px 0 0;
}

.slide-panel.landscape {
  border-radius: 0;
  box-shadow: -2px 0 10px rgb(0 0 0 / 10%);
}

/* Drag handle areas */
.drag-handle-area {
  flex-shrink: 0;
  touch-action: none;
  cursor: grab;
  user-select: none;
}

.drag-handle-area:active {
  cursor: grabbing;
}

/* Portrait: horizontal pill at top */
.portrait-handle {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 28px;
}

.portrait-collapse-btn {
  position: absolute;
  top: 50%;
  right: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  color: #5f6368;
  touch-action: manipulation;
  cursor: pointer;
  background: transparent;
  border: none;
  border-radius: 50%;
  transform: translateY(-50%);
}

.portrait-collapse-btn:active {
  background-color: rgb(0 0 0 / 8%);
}

.portrait-collapse-btn .material-symbols-outlined {
  font-size: 22px;
}

.drag-pill {
  width: 36px;
  height: 4px;
  background-color: #dadce0;
  border-radius: 2px;
}

/* Landscape: vertical bar on left edge */
.landscape-handle {
  position: absolute;
  top: 0;
  left: -12px;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 100%;
}

.drag-bar {
  width: 4px;
  height: 48px;
  background-color: #dadce0;
  border-radius: 2px;
}

.landscape-handle:hover .drag-bar {
  background-color: #bbb;
}

.landscape-collapse-btn {
  position: absolute;
  top: 50%;
  left: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  color: #5f6368;
  touch-action: manipulation;
  cursor: pointer;
  background: transparent;
  border: none;
  border-radius: 50%;
  transform: translate(-50%, -50%);
}

.landscape-collapse-btn:active {
  background-color: rgb(0 0 0 / 8%);
}

.landscape-collapse-btn .material-symbols-outlined {
  font-size: 20px;
}

/* Inner layout */
.slide-panel-inner {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

.slide-panel.portrait .slide-panel-inner {
  height: calc(100% - 28px); /* subtract handle height */
}

.slide-panel-header {
  flex-shrink: 0;
}

.slide-panel-content {
  flex: 1;

  /* Contain scroll chaining so flinging past the end of the panel never
     scrolls the page/map behind it. */
  overflow: hidden auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

/* Smooth max-height transition during snap animation */
.slide-panel.portrait.is-animating .slide-panel-inner {
  transition: max-height 0.3s cubic-bezier(0.77, 0, 0.175, 1);
}

/* Disable scrollbar flicker during drag */
.slide-panel.is-dragging .slide-panel-content {
  overflow: hidden;
}

/* Dark-mode rules live inside SlidePanel.svelte's \3c style> block so :global()
   compiles correctly. */

  /* Dark mode lives here in the Svelte \3c style> block (not the imported CSS
     file) so :global() reliably reaches the compiler. Selectors use the
     class-based dark mode set up by $lib/utils/theme.ts on <html class="dark">. */
  html.dark .slide-panel {
    background-color: #1f2937;
    color: #f3f4f6;
    box-shadow: 0 -2px 10px rgb(0 0 0 / 50%);
  }
  html.dark .slide-panel.landscape {
    box-shadow: -2px 0 10px rgb(0 0 0 / 50%);
  }
  html.dark .drag-pill,
  html.dark .drag-bar {
    background-color: #4b5563;
  }
  html.dark .landscape-handle:hover .drag-bar {
    background-color: #6b7280;
  }
  html.dark .portrait-collapse-btn,
  html.dark .landscape-collapse-btn {
    color: #d1d5db;
  }
  html.dark .portrait-collapse-btn:active,
  html.dark .landscape-collapse-btn:active {
    background-color: rgb(255 255 255 / 8%);
  }


  /* The container every @container query below resolves against. The POI panel
     is a fixed-width rail in landscape and the window in portrait, so its width
     is a property of the PANEL and not of the viewport. */
  .wse.svelte-10r4ge5 {
      container-type: inline-size;
      container-name: wse;
      box-sizing: border-box;
      width: 100%;
      padding: 12px 16px;
      font-family: "Open Sans", sans-serif;
      font-size: 13px;
      line-height: 1.5;
      color: #333;
      border-bottom: 1px solid #eee;
  }

  .wse-title.svelte-10r4ge5 {
      margin: 0 0 4px;
      font-size: 12px;
      font-weight: 700;
      letter-spacing: 0.02em;
      text-transform: uppercase;
      color: #6b7280;
  }

  .wse-title-meta.svelte-10r4ge5 {
      /* Undoes the heading's own casing and weight rather than picking new
         ones: a date reads as a date, and an uppercased "Thu 17 Sep" is harder
         to scan than the thing it labels. Colour is deliberately NOT set, so
         the dark-mode rule on `.wse-title` carries it. */
      font-weight: 400;
      text-transform: none;
      letter-spacing: normal;
      /* The score keeps the heading's own weight (see `.wse-title-score`); only
         the period steps down, so the number stays as prominent as the pill it
         is explaining. */
      /* The period wraps like everything else here. Holding it on one line was
         tried and reverted: on the narrowest panel a long locale's date is
         wider than the column, so an unwrappable run would overflow where a
         wrapped one merely takes a second line. Nothing in this section clips —
         the source check below pins that for the whole file. */
      overflow-wrap: break-word;
  }

  .wse-title-score.svelte-10r4ge5 {
      /* The one number the whole section is about, so it carries the heading's
         weight back. Stated rather than inherited: `.wse-title-meta` sets 400
         on the span this sits inside, and inheriting would pick that up. */
      font-weight: 700;
  }

  .wse-verdict.svelte-10r4ge5 {
      /* Long locales wrap. Nothing here clips and nothing ellipsises: the
         verdict is the one line the section exists for. */
      margin: 0;
      font-size: 14px;
      overflow-wrap: break-word;
  }

  .wse-levers.svelte-10r4ge5 {
      margin: 8px 0 0;
      padding: 0;
      list-style: none;
      display: flex;
      flex-direction: column;
      gap: 6px;
  }

  .wse-lever.svelte-10r4ge5 {
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      gap: 2px;
  }

  .wse-lever-text.svelte-10r4ge5 {
      overflow-wrap: break-word;
  }

  .wse-lever-link.svelte-10r4ge5 {
      padding: 0;
      border: 0;
      background: none;
      font: inherit;
      color: #1976d2;
      text-align: start;
      text-decoration: underline;
      cursor: pointer;
  }

  .wse-actions.svelte-10r4ge5 {
      /* Every control in the section shares this line. `wrap` because at the
         narrowest container width three links plus a chevron do not fit — and
         in Hebrew or Greek two already do not — so the line must break rather
         than overflow; nothing in this section clips. The line's own top
         margin replaces the toggle's, which is why the toggle no longer
         carries one. */
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: 6px 16px;
      margin-top: 8px;
  }

  .wse-toggle.svelte-10r4ge5 {
      display: inline-flex;
      align-items: center;
      gap: 4px;
      padding: 0;
      border: 0;
      background: none;
      font: inherit;
      font-weight: 600;
      color: #1976d2;
      cursor: pointer;
  }

  .wse-chevron.svelte-10r4ge5 {
      font-size: 18px;
      line-height: 1;
      transition: transform 0.15s;
  }

  .wse-toggle[aria-expanded="true"].svelte-10r4ge5 .wse-chevron:where(.svelte-10r4ge5) {
      transform: rotate(90deg);
  }

  /* RTL: the chevron points the other way before it rotates. */
  .wse[dir="rtl"].svelte-10r4ge5 .wse-chevron:where(.svelte-10r4ge5) {
      transform: rotate(180deg);
  }

  .wse[dir="rtl"].svelte-10r4ge5 .wse-toggle[aria-expanded="true"]:where(.svelte-10r4ge5) .wse-chevron:where(.svelte-10r4ge5) {
      transform: rotate(90deg);
  }

  .wse-breakdown.svelte-10r4ge5 {
      display: none;
  }

  .wse-breakdown.is-open.svelte-10r4ge5 {
      display: block;
      margin-top: 8px;
  }

  .wse-ledger.svelte-10r4ge5 {
      width: 100%;
      margin: 0;
      border-collapse: collapse;
      /* Auto layout on purpose: the value column is sized by its widest entry
         (see `.wse-ledger-title`'s width), which is what lets the values share
         one right edge. No breakpoint — a line is its title and its value on
         one row at EVERY width; the title wraps, the value never does. */
      table-layout: auto;
  }

  .wse-ledger-row.svelte-10r4ge5 > th:where(.svelte-10r4ge5),
  .wse-ledger-row.svelte-10r4ge5 > td:where(.svelte-10r4ge5) {
      padding: 2px 0;
      vertical-align: baseline;
  }

  .wse-ledger-title.svelte-10r4ge5 {
      /* 100% is the auto-layout idiom for "everything the other column does
         not need": the value column collapses to its widest entry and this one
         takes the rest, wrapping as it must. `th` defaults undone: a row
         header here is a label, not a heading. */
      width: 100%;
      font-weight: 400;
      text-align: start;
      color: #4b5563;
      overflow-wrap: break-word;
      padding-inline-end: 12px;
  }

  .wse-ledger-value.svelte-10r4ge5 {
      /* Physically right, in BOTH directions: the values are LTR numeric runs
         whatever the sentence direction, and their rightmost digits — the one
         beside the % — must sit on one vertical line. In RTL the column lands
         at the row's far end (the left) and the numbers align on its right,
         toward the title. */
      white-space: nowrap;
      text-align: right;
      font-variant-numeric: tabular-nums;
  }

  .wse-ledger-row.is-maximum.svelte-10r4ge5 .wse-ledger-title:where(.svelte-10r4ge5) {
      /* The opening balance is context, not a finding; it steps back so the
         deductions under it are what the eye lands on. */
      color: #6b7280;
  }

  .wse-ledger-row.is-total.svelte-10r4ge5 > th:where(.svelte-10r4ge5),
  .wse-ledger-row.is-total.svelte-10r4ge5 > td:where(.svelte-10r4ge5) {
      /* The rule sits on both cells so it runs the row's full width. */
      font-weight: 700;
      border-top: 1px solid #e5e7eb;
      padding-top: 5px;
  }

  .wse-ledger-row.is-total.svelte-10r4ge5 .wse-ledger-title:where(.svelte-10r4ge5) {
      color: inherit;
  }

  .wse-ledger-actions.svelte-10r4ge5 {
      /* The expansion's own control row, shaped like `.wse-actions` above it:
         wraps rather than overflows, the FAQ link last. */
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: 6px 16px;
      margin-top: 8px;
  }

  .wse-faq.svelte-10r4ge5 {
      color: #1976d2;
  }

  /* The team line's feedback button: an inline icon riding the title's last
     line rather than a row of its own. */
  .wse-feedback.svelte-10r4ge5 {
      display: inline-flex;
      vertical-align: middle;
      margin-inline-start: 6px;
      padding: 0;
      border: 0;
      background: none;
      color: #1976d2;
      cursor: pointer;
  }

  .wse-feedback.svelte-10r4ge5 .material-symbols-outlined:where(.svelte-10r4ge5) {
      font-size: 18px;
  }

  /* ≥ 480px — landscape `wide` (max(408, 50vw); ≈688px of content on a desktop).
     A lever's sentence and its link now fit on one line. */
  @container wse (min-width: 480px) {
      .wse-lever.svelte-10r4ge5 {
          flex-direction: row;
          align-items: baseline;
          gap: 8px;
      }

      .wse-lever-text.svelte-10r4ge5 {
          flex: 1 1 auto;
      }

      .wse-lever-link.svelte-10r4ge5 {
          flex: none;
      }
  }

  html.dark .wse.svelte-10r4ge5 {
      color: #e5e7eb;
      border-bottom-color: #374151;
  }

  html.dark .wse-title.svelte-10r4ge5,
  html.dark .wse-ledger-row.is-maximum.svelte-10r4ge5 .wse-ledger-title:where(.svelte-10r4ge5) {
      color: #9ca3af;
  }

  html.dark .wse-ledger-title.svelte-10r4ge5 {
      color: #d1d5db;
  }

  html.dark .wse-ledger-row.is-total.svelte-10r4ge5 > th:where(.svelte-10r4ge5),
  html.dark .wse-ledger-row.is-total.svelte-10r4ge5 > td:where(.svelte-10r4ge5) {
      border-top-color: #374151;
  }

  html.dark .wse-lever-link.svelte-10r4ge5,
  html.dark .wse-toggle.svelte-10r4ge5,
  html.dark .wse-faq.svelte-10r4ge5 {
      color: #60a5fa;
  }

/* InfoPanel content styles - positioning handled by SlidePanel */

.poi-header {
  position: relative;
  display: flex;
  flex-flow: column wrap;
  gap: 10px;
  row-gap: 2px;
  align-items: flex-start;
  font-family: "Open Sans", sans-serif;

  .back-button {
    position: absolute;
    top: 6px;
    left: 0;
  }

  .poi-title-row {
    display: flex;
    gap: 8px;
    align-items: flex-start;
    width: 100%;
    padding: 12px 16px 0;
  }

  .poi-header-actions {
    display: flex;
    flex-shrink: 0;
    gap: 8px;
    align-items: center;
  }

  .close-button {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    cursor: pointer;
    background: #f0f0f0;
    border: none;
    border-radius: 50%;
  }

  .draft-tag {
    padding: 2px 8px;
    font-size: 12px;
    font-weight: 600;
    color: #b45309;
    background: #fef3c7;
    border: 1px solid #f59e0b;
    border-radius: 4px;
  }

  .edit-location-button {
    cursor: pointer;
    background: transparent;
    border: 0;
  }

  .edit-location-button .material-symbols-outlined {
    font-size: 28px;
  }

  .report-button {
    cursor: pointer;
    background: transparent;
    border: 0;
  }

  .report-button .material-symbols-outlined {
    font-size: 28px;
  }

  .add-to-itinerary-button {
    display: flex;
    gap: 6px;
    align-items: center;
    justify-content: center;
    width: calc(100% - 32px);
    padding: 8px 16px;
    margin: 0 16px;
    font-family: "Open Sans", sans-serif;
    font-size: 14px;
    font-weight: 500;
    color: white;
    cursor: pointer;
    background: #4caf50;
    border: none;
    border-radius: 8px;
    transition:
      background-color 0.2s ease,
      opacity 0.2s ease;
  }

  .add-to-itinerary-button:hover {
    background: #388e3c;
  }

  .add-to-itinerary-button .material-symbols-outlined {
    font-size: 20px;
  }

  .add-to-itinerary-button .button-text {
    white-space: nowrap;
  }

  .add-to-itinerary-button.add-again {
    background: #1976d2;
  }

  .add-to-itinerary-button.add-again:hover {
    background: #1565c0;
  }

  /* Split "Add to itinerary": main zone (direct add to the last day) +
     arrow zone (day dropdown). The two buttons share one pill silhouette —
     the split lives on the wrapper, each half dropping the outer margin and
     the facing corner radii, with a hairline divider between them. */
  .add-to-itinerary-wrap {
    position: relative;
  }

  .add-to-itinerary-split {
    display: flex;
    align-items: stretch;
    width: calc(100% - 32px);
    margin: 0 16px;
  }

  .add-to-itinerary-split .add-to-itinerary-button {
    width: auto;
    margin: 0;
  }

  .add-to-itinerary-split .add-to-itinerary-main {
    flex: 1;
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
  }

  .add-to-itinerary-split .add-to-itinerary-arrow {
    flex: 0 0 auto;
    padding: 8px 6px;
    border-left: 1px solid rgb(255 255 255 / 35%);
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
  }

  .add-to-itinerary-button .day-menu-caret {
    margin-left: auto;
  }

  /* Keep the trigger above the click-away backdrop while the menu is open so
     it stays interactive (toggle-to-close) and shows hover/active states. */
  .add-to-itinerary-split.day-menu-open {
    position: relative;
    z-index: 12;
  }

  .dblclick-add-hint {
    width: calc(100% - 32px);
    margin: 4px 16px 0;
    font-family: "Open Sans", sans-serif;
    font-size: 12px;
    line-height: 1.3;
    color: #6b7280;
  }

  /* The marker double-click shortcut needs a mouse. */
  @media (hover: none), (pointer: coarse) {
    .dblclick-add-hint {
      display: none;
    }
  }

  .day-menu-backdrop {
    position: fixed;
    inset: 0;
    z-index: 10;
  }

  .day-menu {
    position: absolute;
    top: calc(100% + 6px);
    right: 16px;
    left: 16px;
    z-index: 11;
    display: flex;
    flex-direction: column;
    max-height: 240px;
    padding: 6px;
    overflow-y: auto;
    background: white;
    border: 1px solid #e5e7eb;
    border-radius: 10px;
    box-shadow: 0 8px 24px rgb(0 0 0 / 18%);
  }

  .day-menu-title {
    padding: 4px 8px 6px;
    font-family: "Open Sans", sans-serif;
    font-size: 12px;
    font-weight: 600;
    color: #6b7280;
  }

  .day-menu-item {
    padding: 8px 10px;
    font-family: "Open Sans", sans-serif;
    font-size: 14px;
    color: #1f2937;
    text-align: left;
    cursor: pointer;
    background: none;
    border: none;
    border-radius: 6px;
  }

  .day-menu-item:hover {
    background: #f3f4f6;
  }

  .day-menu-separator {
    height: 1px;
    margin: 4px 6px;
    background: #e5e7eb;
  }

  .back-button .material-symbols-outlined {
    font-size: 28px;
  }

  .poi-title {
    flex: 1;
    min-width: 0;
    margin: 0;
    font-size: 24px;
    font-weight: 500;

    &.no-subtitle {
      padding-bottom: 12px;
    }
  }

  /* The right-hand end of the type/subtype row: the marina "More details"
     menu (havens only) and the locale pill. `margin-inline-start: auto`
     pushes the pair to the row's end and is RTL-safe; it lives here rather
     than on LocalePill so the two stay together when the menu is present. */
  .poi-type-actions {
    display: flex;
    gap: 6px;
    align-items: center;
    margin-inline-start: auto;
  }

  .poi-type {
    display: flex;
    gap: 8px;
    align-items: center;
    width: 100%;
    padding: 0 16px 8px;
    font-size: 14px;
    color: rgb(1 1 1 / 60%);
    text-transform: capitalize;
    border-bottom: 1px solid rgb(0 0 0 / 8%);
  }

  .poi-tags-row {
    width: 100%;
    padding: 8px 16px;
  }

  .location-tags {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 4px;
  }

  .location-tag {
    display: inline-flex;
    padding: 3px 10px;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.2;
    color: #fff;
    text-transform: none;
    background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
    border: 1px solid #b45309;
    border-radius: 10px;
  }
}

.panel-body {
  flex-grow: 1;
  overflow: auto;

  .poi-additional-info {
    position: relative;
    font-family: "Open Sans", sans-serif;
  }

  .poi-about {
    box-sizing: border-box;
    width: 100%;
    padding: 12px 16px;
    font-family: "Open Sans", sans-serif;
    font-size: 16px;
    line-height: 1.5;
    color: #333;
    background: white;

    img {
      max-width: 100%;
      height: auto;
    }

    :global(img) {
      max-width: 100%;
      height: auto;
    }

    iframe {
      width: 100%;
      height: auto;
      aspect-ratio: 16 / 9;
    }

    :global(iframe) {
      width: 100%;
      height: auto;
      aspect-ratio: 16 / 9;
    }

    /* R29 — content links in this sanitized-HTML field get the a-normal
       treatment (blue-600, underlined) via CSS rather than a literal class:
       {@html} output has no template to add `a-normal` to, unlike the
       template-owned links in PoiContactDetails.svelte. Excludes the
       linkifyPhonesInHtml WhatsApp/dial pair (`.about-phone-wa` /
       `.about-phone-tel`), which keeps its own bespoke styling per R29.
       `!important` on colour guards against authored About HTML pinning its
       own inline anchor colour — the same problem the dark-mode rules below
       already have to fight. */
    a:not(.about-phone-wa, .about-phone-tel) {
      color: #2563eb !important;
      text-decoration: underline;
    }

    /* Lists. Tailwind's preflight strips list markers (`list-style: none`),
       and Quill 2 — which authored this HTML — stores bullets AND numbering
       as `<ol>`, recording each item's kind in `data-list` and drawing the
       marker itself only inside its own `.ql-editor`. Without these rules no
       About list shows a bullet or a number here, in any language. */
    ol,
    ul {
      padding-inline-start: 1.5em;
    }

    ul > li,
    li[data-list="bullet"] {
      list-style-type: disc;
    }

    ol > li:not([data-list]),
    li[data-list="ordered"] {
      list-style-type: decimal;
    }

    .google-place-loading {
      display: flex;
      flex-direction: column;
      gap: 12px;
      align-items: center;
      justify-content: center;
      height: 200px;
      font-family: "Open Sans", sans-serif;
      color: #666;

      .spinning {
        font-size: 32px;
        animation: spin 1s linear infinite;
      }
    }
  }

  .google-place-inline {
    flex: 1;
    overflow: auto;
    background: white;

    gmp-place-details {
      display: block;
      width: 100%;
      min-height: 400px;
    }

    .google-place-loading {
      display: flex;
      flex-direction: column;
      gap: 12px;
      align-items: center;
      justify-content: center;
      height: 200px;
      font-family: "Open Sans", sans-serif;
      color: #666;

      .spinning {
        font-size: 32px;
        animation: spin 1s linear infinite;
      }
    }
  }

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

    to {
      transform: rotate(360deg);
    }
  }
}

.google-place-view {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
}

.google-place-floating-buttons {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 10;
  display: flex;
  gap: 8px;

  .back-button,
  .close-button {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    cursor: pointer;
    background: #f0f0f0;
    border: none;
    border-radius: 50%;
  }

  .add-location-button,
  .copy-url-button {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    cursor: pointer;
    background: #f0f0f0;
    border: none;
    border-radius: 50%;
  }
}

.google-place-body {
  flex: 1;
  height: 100%;
  overflow: auto;
  background: white;

  gmp-place-details {
    display: block;
    width: 100%;
    height: 100%;
  }

  .google-place-loading {
    display: flex;
    flex-direction: column;
    gap: 12px;
    align-items: center;
    justify-content: center;
    height: 200px;
    font-family: "Open Sans", sans-serif;
    color: #666;

    .spinning {
      font-size: 32px;
      animation: spin 1s linear infinite;
    }
  }
}

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

  to {
    transform: rotate(360deg);
  }
}

/* U9 — markdown view mode: a curated content page rendered inside the panel.
   Carta emits its own `.markdown-body` wrapper, whose nodes carry no Svelte
   scoping class, so these rules must live here (this file is imported, not
   compiled, and therefore unscoped) rather than in the component's \3c style>. */
.more-details-button {
  display: flex;
  gap: 2px;
  align-items: center;
  padding: 4px 6px 4px 10px;
  font-family: "Open Sans", sans-serif;
  font-size: 13px;
  font-weight: 600;
  color: #333;
  cursor: pointer;
  background: #f0f0f0;
  border: none;
  border-radius: 16px;
}

.more-details-button:hover {
  background: #e4e4e4;
}

.more-details-button .material-symbols-outlined {
  font-size: 20px;
}

.poi-markdown {
  box-sizing: border-box;
  width: 100%;
  padding: 12px 16px;
  font-family: "Open Sans", sans-serif;
  font-size: 16px;
  line-height: 1.5;
  color: #333;
  background: white;
}

/* Carta's viewer defaults to a reading-width column; the panel is already
   narrow, so let it use the full width (the full content page does the same
   from its onMount). */
.poi-markdown .markdown-body {
  max-width: 100%;
}

.poi-markdown img {
  max-width: 100%;
  height: auto;
}

.poi-markdown iframe {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
}

/* R29 — same a-normal-via-CSS treatment as `.poi-about a` above, for the
   Carta-rendered curated markdown page (also runtime HTML with no template
   to add `a-normal` to). No phone-pair exclusion needed here: linkifyPhones
   only runs on the About field, never on markdown content. */
.poi-markdown a {
  color: #2563eb !important;
  text-decoration: underline;
}

.markdown-notice {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  justify-content: center;
  padding: 48px 16px;
  color: #666;
  text-align: center;
}

.markdown-notice .material-symbols-outlined {
  font-size: 32px;
}

.markdown-retry {
  padding: 6px 16px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  color: #333;
  cursor: pointer;
  background: #f0f0f0;
  border: none;
  border-radius: 16px;
}

.markdown-shimmer {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 8px 0;
}

.markdown-shimmer .shimmer {
  background: linear-gradient(90deg, #e0e0e0 25%, #f0f0f0 50%, #e0e0e0 75%);
  background-size: 200% 100%;
  border-radius: 4px;
  animation: shimmer 1.5s infinite;
}

.markdown-shimmer .md-title {
  width: 60%;
  height: 24px;
}

.markdown-shimmer .md-line {
  width: 100%;
  height: 14px;
}

.markdown-shimmer .md-line.short {
  width: 70%;
}

@keyframes shimmer {
  0% {
    background-position: 200% 0;
  }

  100% {
    background-position: -200% 0;
  }
}

/* Dark-mode rules live inside InfoPanel.svelte's \3c style> block (:global()
   fully reaches the Svelte compiler there). */

  /* Coordinate mode — an arbitrary map position picked while editing. */
  .coordinate-latlng.svelte-1rw9vfk {
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
  }

  /* The coordinates line every POI's details carry, under the type row.
     The horizontal padding matches .poi-title-row's 16px so the line
     starts where the name starts. */
  .poi-coords.svelte-1rw9vfk {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 0 16px;
    margin-top: 2px;
    font-size: 12px;
    color: #888;
  }

  .coords-copy-button.svelte-1rw9vfk {
    display: inline-flex;
    align-items: center;
    padding: 0;
    color: inherit;
    background: none;
    border: none;
    cursor: pointer;
  }

  .coords-copy-button.svelte-1rw9vfk:hover {
    color: #333;
  }

  .coords-copy-button.svelte-1rw9vfk .material-symbols-outlined:where(.svelte-1rw9vfk) {
    font-size: 14px;
  }
  /* Dark mode (class-based — :global(html.dark) ...) lives in the Svelte
     \3c style> block so the compiler processes :global() reliably. */
  html.dark .poi-header,
  html.dark .poi-header .close-button,
  html.dark .poi-header .edit-location-button,
  html.dark .poi-header .report-button {
    color: #f3f4f6;
  }
  html.dark .poi-header .close-button {
    background: #374151;
  }
  html.dark .poi-header .draft-tag {
    color: #fbbf24;
    background: #422006;
    border-color: #b45309;
  }
  html.dark .poi-header .poi-type {
    color: rgb(243 244 246 / 75%);
    border-bottom-color: rgb(255 255 255 / 10%);
  }
  html.dark .poi-header .dblclick-add-hint {
    color: rgb(243 244 246 / 60%);
  }
  /* Item 16: phone numbers detected in the about prose render with the Phone
     affordance (WhatsApp launch + dial link), inline within the sentence. */
  .poi-about .about-phone {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    vertical-align: baseline;
    white-space: nowrap;
  }
  .poi-about .about-phone-wa {
    display: inline-flex;
    align-items: center;
    line-height: 0;
  }
  .poi-about .about-phone-wa img {
    width: 16px;
    height: 16px;
  }
  html.dark .panel-body .poi-about {
    color: #f3f4f6;
    background: #1f2937;
  }
  /* Per-line white backgrounds and per-span black text colours
     occasionally creep into POI descriptions (e.g. the Salamis Battle
     entry stored HTML where the editor pinned `color: #000` and a
     white background on each line). Force every descendant to honour
     the panel's dark surface so the text doesn't end up as black on
     white ribbons. */
  html.dark .panel-body .poi-about * {
    background-color: transparent !important;
    color: #f3f4f6 !important;
  }
  /* R29 — content links get the a-normal dark colour (#60a5fa, matching
     `.a-normal`'s `dark:text-blue-400`), not the `#93c5fd` this rule used to
     apply to every link in the field. The linkifyPhonesInHtml WhatsApp/dial
     pair (`.about-phone-wa` / `.about-phone-tel`) is excluded here so the
     dedicated rule below — its own bespoke `#93c5fd`, unchanged — keeps
     winning for those two anchors specifically. */
  html.dark .panel-body .poi-about a:not(.about-phone-wa, .about-phone-tel),
  html.dark .panel-body .poi-about a:not(.about-phone-wa, .about-phone-tel):visited {
    color: #60a5fa !important;
  }
  /* The phone pair's pre-existing bespoke dark-mode colour, unchanged by
     R29 — narrowed off the rule above so it doesn't compete with the
     a-normal treatment now given to the field's other links. */
  html.dark .panel-body .poi-about a.about-phone-wa,
  html.dark .panel-body .poi-about a.about-phone-wa:visited,
  html.dark .panel-body .poi-about a.about-phone-tel,
  html.dark .panel-body .poi-about a.about-phone-tel:visited {
    color: #93c5fd !important;
  }
  html.dark .panel-body .poi-about .google-place-loading,
  html.dark .panel-body .google-place-inline .google-place-loading {
    color: #9ca3af;
  }
  html.dark .panel-body .google-place-inline {
    background: #1f2937;
  }
  /* The <gmp-place-details> Google web component renders inside its own
     shadow DOM and ships a light-only stylesheet, so it punches a white
     rectangle into the otherwise-dark panel. CSS-invert the embed (and
     re-rotate the hue) so it reads as dark while keeping its colours
     roughly the same. Photos rendered inside the embed get their hue
     inverted too — acceptable trade-off until Google ships a dark theme
     for the component. */
  html.dark .google-place-inline gmp-place-details,
  html.dark .google-place-body gmp-place-details {
    filter: invert(1) hue-rotate(180deg);
    background: transparent;
  }
  html.dark .google-place-inline gmp-place-details img,
  html.dark .google-place-body gmp-place-details img {
    /* Cancel out the parent invert/hue-rotate on photos so they render
       with their original colours. */
    filter: invert(1) hue-rotate(180deg);
  }
  html.dark .google-place-floating-buttons .back-button,
  html.dark .google-place-floating-buttons .close-button,
  html.dark .google-place-floating-buttons .add-location-button,
  html.dark .google-place-floating-buttons .copy-url-button {
    color: #f3f4f6;
    background: #374151;
  }
  html.dark .google-place-body {
    background: #1f2937;
  }
  html.dark .google-place-body .google-place-loading {
    color: #9ca3af;
  }
  /* U9 — markdown view mode. Same treatment, and same reason, as `.poi-about`
     above: authored content routinely carries per-line white backgrounds and
     pinned `color: #000`, which render as black-on-white ribbons across a dark
     panel. Force every descendant onto the panel's dark surface. Carta's own
     `.markdown-body` nodes are inside {@html} output, so all of this has to be
     `:global()`. */
  html.dark .poi-header .more-details-button {
    color: #f3f4f6;
    background: #374151;
  }
  html.dark .poi-header .more-details-button:hover {
    background: #4b5563;
  }
  /* Tables in curated documents — the seamark legend is one symbol per row,
     image in the first column, meaning in the second. The markdown stylesheet
     sets every image as a block with generous vertical margins, which in a
     table cell stretches each row to ~160px with the text baseline-aligned
     at the bottom, and its `max-width: 100%` lets the auto layout squeeze
     the symbol column. Inside a cell an image is inline on the middle line
     and the row hugs it. A cell image is one fixed-height tile — 56px, its
     width from its aspect ratio — so a column of them reads as equal tiles
     regardless of the source's pixel size: the legend renders every symbol
     onto the same 240x112 canvas (shown here at half size, retina-sharp),
     single symbols at one uniform icon size inside it, composites and
     diagrams filling it. Carta's output is {@html}, so the descendants need
     `:global()`. */
  .poi-markdown.svelte-1rw9vfk table {
    width: 100%;
  }
  .poi-markdown.svelte-1rw9vfk th,
  .poi-markdown.svelte-1rw9vfk td {
    vertical-align: middle;
  }
  .poi-markdown.svelte-1rw9vfk td img {
    display: inline-block;
    margin: 0;
    height: 56px;
    width: auto;
    /* Not the stylesheet's `max-width: 100%`: with the height pinned, a
       shrinkable width lets the auto table layout squeeze the symbol
       column and the image with it — circles became ellipses. The tile is
       120px wide; the cell takes it. */
    max-width: none;
    vertical-align: middle;
  }
  html.dark .panel-body .poi-markdown {
    color: #f3f4f6;
    background: #1f2937;
  }
  html.dark .panel-body .poi-markdown * {
    background-color: transparent !important;
    color: #f3f4f6 !important;
  }
  /* R29 — a-normal dark colour (#60a5fa), replacing the ad-hoc #93c5fd.
     No phone-pair exclusion needed: linkifyPhones never runs on markdown
     content, only on the About field (see the .poi-about rule above). */
  html.dark .panel-body .poi-markdown a,
  html.dark .panel-body .poi-markdown a:visited {
    color: #60a5fa !important;
  }
  /* Code blocks and quotes need a surface, which the blanket `transparent`
     above strips; give them a dark one back. */
  html.dark .panel-body .poi-markdown pre,
  html.dark .panel-body .poi-markdown code {
    background-color: #111827 !important;
  }
  html.dark .panel-body .poi-markdown blockquote {
    border-left-color: #4b5563;
  }
  html.dark .panel-body .markdown-notice,
  html.dark .panel-body .markdown-notice * {
    color: #9ca3af !important;
  }
  html.dark .panel-body .markdown-retry {
    color: #f3f4f6 !important;
    background: #374151 !important;
  }
  html.dark .panel-body .markdown-shimmer .shimmer {
    background: linear-gradient(90deg, #374151 25%, #4b5563 50%, #374151 75%) !important;
    background-size: 200% 100%;
  }

  html.dark .day-menu.svelte-1rw9vfk {
    background: #1f2937;
    border-color: #374151;
  }
  html.dark .day-menu-title.svelte-1rw9vfk {
    /* Lighter than #9ca3af to clear WCAG AA (4.5:1) on the #1f2937 menu bg. */
    color: #cbd5e1;
  }
  html.dark .day-menu-item.svelte-1rw9vfk {
    color: #f3f4f6;
  }
  html.dark .day-menu-item.svelte-1rw9vfk:hover {
    background: #374151;
  }
  html.dark .day-menu-separator.svelte-1rw9vfk {
    background: #374151;
  }


  .shimmer-wrapper.svelte-1tm4o7z {
    position: relative;
    overflow: hidden;
    background-color: #e0e0e0;
    height:150px;
  }

  .shimmer.svelte-1tm4o7z {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(
      to right,
      transparent 0%,
      rgba(255, 255, 255, 0.6) 50%,
      transparent 100%
    );
    animation: svelte-1tm4o7z-shimmer 1.5s infinite;
  }

  @keyframes svelte-1tm4o7z-shimmer {
    0% {
      transform: translateX(-100%);
    }
    100% {
      transform: translateX(100%);
    }
  }

  html.dark .shimmer-wrapper.svelte-1tm4o7z {
    background-color: #374151;
  }
  html.dark .shimmer.svelte-1tm4o7z {
    background: linear-gradient(
      to right,
      transparent 0%,
      rgba(255, 255, 255, 0.08) 50%,
      transparent 100%
    );
  }


  .itineraries-grid.svelte-1444lfa {
    display: grid;
    grid-template-columns: 1fr;
    grid-template-rows: 150px;
    gap: 16px;
  }

  .itinerary-item-shimmer.svelte-1444lfa {
    width: 100%;
    height: 150px;
    position: relative;
  }

  .itinerary-item-shimmer.svelte-1444lfa .shimmer-wrapper {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    border-radius: 8px;
  }


  .details-header.svelte-tarnde {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px 16px;
    gap: 16px;
  }

  .itinerary-title-container.svelte-tarnde {
    flex: 1;
    min-width: 0;
  }

  .itinerary-actions.svelte-tarnde {
    display: flex;
    gap: 8px;
  }

  .itinerary-separator.svelte-tarnde {
    height: 1px;
    background-color: #cacaca;
  }

  .itinerary-panel-body.svelte-tarnde {
    padding: 20px;
  }

  .itinerary-steps.svelte-tarnde {
    padding: 0 24px;
  }

  .step-shimmer.svelte-tarnde {
    display: flex;
    min-height: 120px;
    padding: 12px 0;
  }

  .step-shimmer.svelte-tarnde:last-child .step-line:where(.svelte-tarnde) {
    display: none;
  }

  .step-icon-container.svelte-tarnde {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-right: 8px;
  }

  .step-line.svelte-tarnde {
    width: 2px;
    background-color: #e0e0e0;
    flex-grow: 1;
    margin-top: 8px;
  }

  .step-content.svelte-tarnde {
    flex-grow: 1;
    padding-top: 12px;
  }

  .shimmer.svelte-tarnde {
    background: linear-gradient(90deg, #e0e0e0 25%, #f0f0f0 50%, #e0e0e0 75%);
    background-size: 200% 100%;
    animation: svelte-tarnde-shimmer 1.5s infinite;
    border-radius: 4px;
  }

  .shimmer.title.svelte-tarnde {
    height: 24px;
    width: 60%;
    margin-bottom: 8px;
  }

  .shimmer.subtitle.svelte-tarnde {
    height: 14px;
    width: 80px;
  }

  .shimmer.icon-button.svelte-tarnde {
    width: 32px;
    height: 32px;
    border-radius: 50%;
  }

  .shimmer.step-icon.svelte-tarnde {
    width: 48px;
    height: 48px;
    border-radius: 50%;
  }

  .shimmer.step-title.svelte-tarnde {
    height: 18px;
    width: 50%;
    margin-bottom: 12px;
  }

  .shimmer.step-text.svelte-tarnde {
    height: 14px;
    width: 100%;
    margin-bottom: 8px;
  }

  .shimmer.step-text.short.svelte-tarnde {
    width: 70%;
  }

  @keyframes svelte-tarnde-shimmer {
    0% {
      background-position: 200% 0;
    }
    100% {
      background-position: -200% 0;
    }
  }

  html.dark .itinerary-separator.svelte-tarnde {
    background-color: #374151;
  }
  html.dark .step-line.svelte-tarnde {
    background-color: #374151;
  }
  html.dark .shimmer.svelte-tarnde {
    background: linear-gradient(90deg, #374151 25%, #4b5563 50%, #374151 75%);
    background-size: 200% 100%;
  }


  /* Inherits styles from ItineraryPanel.css */
  .proposal-alert.svelte-1nwng5r {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    padding: 16px;
    margin: 12px 0;
    border-radius: 12px;
    animation: svelte-1nwng5r-slideDown 0.3s ease-out;
  }

  .proposal-alert.svelte-1nwng5r .material-symbols-outlined:where(.svelte-1nwng5r) {
    font-size: 24px;
    color: #2196f3;
  }

  .proposal-content.svelte-1nwng5r {
    flex: 1;
  }

  .proposal-card-content.svelte-1nwng5r {
    margin-bottom: 8px;
    font-size: 14px;
    color: #333;
  }

  .proposal-actions.svelte-1nwng5r {
    display: flex;
    gap: 8px;
  }

  .proposal-actions.svelte-1nwng5r button:where(.svelte-1nwng5r) {
    padding: 6px 12px;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    border-radius: 6px;
    transition: opacity 0.2s;
  }

  .proposal-actions.svelte-1nwng5r button:where(.svelte-1nwng5r):hover {
    opacity: 0.8;
  }

  .accept-button.svelte-1nwng5r {
    color: white;
    background-color: #2196f3;
    border: none;
  }

  .ignore-button.svelte-1nwng5r {
    color: #666;
    background-color: transparent;
    border: 1px solid #ccc;
  }

  .extra-button.svelte-1nwng5r {
    color: #999;
    background-color: transparent;
    border: 1px solid #ddd;
  }

  .reorder-proposal.svelte-1nwng5r {
    border: 1px solid #2196f3;
  }

  .warning-proposal.svelte-1nwng5r {
    border: 1px solid #ff9800;
  }

  .warning-proposal.svelte-1nwng5r .material-symbols-outlined:where(.svelte-1nwng5r) {
    color: #ff9800;
  }

  .warning-proposal.svelte-1nwng5r .accept-button:where(.svelte-1nwng5r) {
    background-color: #ff9800;
  }

  .proposal-alert.compact.svelte-1nwng5r {
    padding: 8px 12px;
    margin: 4px 0 4px 42px;
    font-size: 13px;
    background-color: rgb(33 150 243 / 5%);
    border-style: dashed;
    box-shadow: none;

    .material-symbols-outlined:where(.svelte-1nwng5r) {
      font-size: 20px;
    }

    .proposal-card-content:where(.svelte-1nwng5r) {
      margin-bottom: 4px;
    }

    .proposal-actions:where(.svelte-1nwng5r) button:where(.svelte-1nwng5r) {
      padding: 4px 8px;
      font-size: 12px;
    }
  }

  .proposal-alert.compact.warning-proposal.svelte-1nwng5r {
    background-color: rgb(255 152 0 / 5%);
  }

  .insert-proposal.svelte-1nwng5r {
    background-color: rgb(255 183 77 / 20%);
    border: 1px solid #ffb74d;
  }

  .insert-proposal.svelte-1nwng5r .material-symbols-outlined:where(.svelte-1nwng5r) {
    color: #f57c00;
  }

  .insert-proposal.svelte-1nwng5r .accept-button:where(.svelte-1nwng5r) {
    background-color: #f57c00;
  }

  .proposal-alert.compact.insert-proposal.svelte-1nwng5r {
    background-color: rgb(255 183 77 / 15%);
  }

  @keyframes svelte-1nwng5r-slideDown {
    from {
      opacity: 0;
      transform: translateY(-10px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }

  /* Class-based dark mode (html.dark). The proposal alert lives inside
     the InfoPanel/ItineraryPanel surface, so all the dim grays here need
     light replacements. The brand blue / amber accents stay. */
  html.dark .proposal-card-content.svelte-1nwng5r {
    color: #f3f4f6;
  }
  html.dark .ignore-button.svelte-1nwng5r {
    color: #d1d5db;
    border-color: #4b5563;
  }
  html.dark .extra-button.svelte-1nwng5r {
    color: #9ca3af;
    border-color: #4b5563;
  }


  .day-date-calendar.svelte-12p3lq2 {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 30;
    width: 232px;
    padding: 0.5rem;
    font-size: 0.8125rem;
    color: #1f2937;
    cursor: default;
    background: #ffffff;
    border: 1px solid var(--color-slate-300, #cbd5e1);
    border-radius: 0.5rem;
    box-shadow: 0 8px 24px rgb(15 23 42 / 18%);
  }

  /* Anchored mode: escape the day group's / panel's overflow clipping. */
  .day-date-calendar.anchored.svelte-12p3lq2 {
    position: fixed;
    z-index: 1200;
  }
  .ddc-header.svelte-12p3lq2 {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 0.25rem;
  }
  .ddc-title.svelte-12p3lq2 {
    font-weight: 600;
  }
  .ddc-nav.svelte-12p3lq2 {
    background: none;
    border: none;
    padding: 0.125rem;
    cursor: pointer;
    color: inherit;
    border-radius: 0.25rem;
    display: inline-flex;
  }
  .ddc-nav.svelte-12p3lq2:hover {
    background: rgba(100, 116, 139, 0.15);
  }
  .ddc-nav.svelte-12p3lq2 .material-symbols-outlined:where(.svelte-12p3lq2) {
    font-size: 18px;
  }
  .ddc-grid.svelte-12p3lq2 {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 1px;
  }
  .ddc-weekday.svelte-12p3lq2 {
    text-align: center;
    font-size: 0.6875rem;
    color: #64748b;
    padding: 0.125rem 0;
  }
  .ddc-day.svelte-12p3lq2 {
    background: none;
    border: none;
    font: inherit;
    color: inherit;
    text-align: center;
    padding: 0.2rem 0;
    border-radius: 0.25rem;
    cursor: pointer;
  }
  .ddc-day.svelte-12p3lq2:hover {
    background: rgba(100, 116, 139, 0.15);
  }
  .ddc-day.selected.svelte-12p3lq2 {
    background: #0e7490;
    color: #ffffff;
    font-weight: 600;
  }
  .ddc-blank.svelte-12p3lq2 {
    cursor: default;
    pointer-events: none;
  }

  html.dark .day-date-calendar.svelte-12p3lq2 {
    background: #1f2937;
    border-color: #4b5563;
    color: #f3f4f6;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
  }
  html.dark .ddc-weekday.svelte-12p3lq2 {
    color: #9ca3af;
  }
  html.dark .ddc-nav.svelte-12p3lq2:hover,
  html.dark .ddc-day.svelte-12p3lq2:hover {
    background: rgba(148, 163, 184, 0.2);
  }
  html.dark .ddc-day.selected.svelte-12p3lq2 {
    background: #22d3ee;
    color: #0f172a;
  }


  /* The menu's LOOK is the app's, not this component's: every `.share-menu-*`
     rule below the container lives in
     routes/[[t=t]]/(unlogged)/map/ItineraryPanel.css, which that panel
     @imports into a global sheet. Re-declaring them here would silently WIN
     (a Svelte-scoped selector outranks the plain global one) and restyle a
     shipped menu for no reason. So this block carries only what the global
     sheet has no rule for. */

  /* Anchored INSIDE the tile so the dropdown cannot be half-cut at the bottom
     edge of the scrolling list. `position: relative` is also in the global
     sheet; the inline-flex is what keeps the trigger sized to its icon when
     the menu sits in a tile's control cluster rather than a toolbar. */
  .share-menu-container.svelte-y3lorf {
    display: inline-flex;
  }

  /* Row 3: a status, not a button — so it gets the item's layout without the
     button affordances. */
  .share-menu-status.svelte-y3lorf {
    display: flex;
    gap: 12px;
    align-items: center;
    width: 100%;
    padding: 14px 16px;
    font-size: 14px;
    font-weight: 500;
    cursor: default;
    opacity: 0.75;
  }

  /* Per-itinerary failure copy. Inline rather than a toast: a toast is global
     state, and the whole point of U17 is that one tile's failure must not
     appear to belong to another's menu. */
  .share-menu-error.svelte-y3lorf {
    padding: 4px 16px 8px;
    color: #ef4444;
    font-size: 13px;
  }

  /* U18's touch-target floor, additive over the global padding. */
  .share-menu-item.svelte-y3lorf,
  .share-menu-toggle-item.svelte-y3lorf {
    min-height: 44px;
  }


  .weather-section.svelte-x97k5r {
    background: var(--color-slate-50, #f8fafc);
    border: 1px solid var(--color-slate-200, #e2e8f0);
    border-radius: 0.5rem;
    margin-bottom: 0.5rem;
    overflow: visible; /* allow popover to escape */
  }

  html.dark .weather-section.svelte-x97k5r {
    background: var(--color-slate-800, #1e293b);
    border-color: var(--color-slate-700, #334155);
  }

  .weather-section-summary.svelte-x97k5r {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    cursor: pointer;
    padding: 0.375rem 0.75rem;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--color-slate-700, #334155);
    user-select: none;
  }

  /* The disclosure toggle — a real <button> so it is keyboard-reachable and
     carries aria-expanded. Reset to render exactly like the bare chevron
     span it replaced. align-self: flex-start so it stays on the title row
     when the legend wraps to a second line. */
  .weather-toggle.svelte-x97k5r {
    display: flex;
    flex-shrink: 0;
    align-self: flex-start;
    padding: 0;
    margin: 0;
    cursor: pointer;
    background: none;
    border: none;
  }

  /* Chevron rotates 90° when open. */
  .weather-chevron.svelte-x97k5r {
    font-size: 18px;
    color: var(--color-slate-400, #94a3b8);
    transition: transform 0.2s ease;
  }

  .weather-section.weather-open.svelte-x97k5r > .weather-section-summary:where(.svelte-x97k5r) .weather-chevron:where(.svelte-x97k5r) {
    transform: rotate(90deg);
  }

  .weather-summary-content.svelte-x97k5r {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.25rem;
    flex: 1;
    min-width: 0;
  }

  .weather-title.svelte-x97k5r {
    font-weight: 600;
    color: var(--color-slate-700, #334155);
  }

  html.dark .weather-title.svelte-x97k5r {
    color: var(--color-slate-100, #f1f5f9);
  }

  .weather-historical-badge.svelte-x97k5r {
    font-size: 0.6875rem;
    color: var(--color-amber-700, #b45309);
    background: var(--color-amber-50, #fffbeb);
    border: 1px solid var(--color-amber-200, #fde68a);
    border-radius: 0.25rem;
    padding: 0 0.25rem;
  }

  .weather-shimmer-title.svelte-x97k5r {
    display: inline-block;
    height: 1rem;
    width: 7rem;
    border-radius: 0.25rem;
    background: var(--color-slate-200, #e2e8f0);
    opacity: 0.6;
    animation: svelte-x97k5r-pulse 1.5s ease-in-out infinite;
    vertical-align: middle;
  }

  @keyframes svelte-x97k5r-pulse {
    0%, 100% { opacity: 0.6; }
    50% { opacity: 0.3; }
  }

  /* ── Info icon + popover ── */

  .weather-info-anchor.svelte-x97k5r {
    position: relative;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    margin-inline-start: auto;
    align-self: flex-end;
    cursor: pointer;
  }

  .weather-info-anchor.svelte-x97k5r:focus {
    outline: none;
  }

  .weather-info-icon.svelte-x97k5r {
    font-size: 16px;
    color: var(--color-slate-400, #94a3b8);
    transition: color 0.15s;
  }

  .weather-info-anchor.svelte-x97k5r:hover .weather-info-icon:where(.svelte-x97k5r),
  .weather-info-anchor.svelte-x97k5r:focus-visible .weather-info-icon:where(.svelte-x97k5r) {
    color: var(--color-slate-600, #475569);
  }

  .weather-info-popover.svelte-x97k5r {
    position: absolute;
    top: calc(100% + 6px);
    inset-inline-end: 0;
    z-index: 50;
    width: 300px;
    background: white;
    border: 1px solid var(--color-slate-200, #e2e8f0);
    border-radius: 0.5rem;
    box-shadow: 0 4px 16px rgb(0 0 0 / 12%);
    padding: 0.625rem 0.75rem 0.625rem 0.75rem;
  }

  html.dark .weather-info-popover.svelte-x97k5r {
    background: var(--color-slate-800, #1e293b);
    border-color: var(--color-slate-600, #475569);
    box-shadow: 0 4px 16px rgb(0 0 0 / 40%);
  }

  .weather-info-close.svelte-x97k5r {
    position: absolute;
    top: 0.25rem;
    right: 0.25rem;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    background: transparent;
    border: none;
    cursor: pointer;
    color: var(--color-slate-400, #94a3b8);
    padding: 0;
  }

  .weather-info-close.svelte-x97k5r .material-symbols-outlined:where(.svelte-x97k5r) {
    font-size: 14px;
  }

  .weather-info-close.svelte-x97k5r:hover {
    color: var(--color-slate-600, #475569);
  }

  .weather-info-text.svelte-x97k5r {
    margin: 0;
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--color-slate-600, #475569);
    padding-right: 1rem; /* space for × button */
  }

  .weather-info-text.svelte-x97k5r + .weather-info-text:where(.svelte-x97k5r) {
    margin-top: 0.6rem;
  }

  html.dark .weather-info-text.svelte-x97k5r {
    color: var(--color-slate-300, #cbd5e1);
  }

  /* ── Body ── */

  .weather-body.svelte-x97k5r {
    padding: 0.125rem 0.75rem 0.5rem;
  }

  /* Collapsed: hide the region (was <details>'s native behavior). Kept in
     the DOM so aria-controls always resolves and weather stays warm. */
  .weather-section.svelte-x97k5r:not(.weather-open) > .weather-body:where(.svelte-x97k5r) {
    display: none;
  }

  .weather-lines.svelte-x97k5r {
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--color-slate-600, #475569);
  }

  html.dark .weather-lines.svelte-x97k5r {
    color: var(--color-slate-300, #cbd5e1);
  }

  /* ── Legend ── */

  .weather-legend.svelte-x97k5r {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    flex-wrap: wrap;
    margin-inline-start: auto;
  }

  /* When the section is collapsed, render the legend as icon-only pills
     (no "Wind kts" / "Waves m/s" text) so the title row stays compact
     while still cueing the colour vocabulary. */
  .weather-section.svelte-x97k5r:not(.weather-open) > .weather-section-summary:where(.svelte-x97k5r) .legend-label:where(.svelte-x97k5r) {
    display: none;
  }

  .weather-legend-pill.svelte-x97k5r {
    font-size: 0.6875rem;
    padding: 0.0625rem 0.375rem;
  }

  .legend-icon.svelte-x97k5r {
    font-size: 11px;
    display: inline-block;
    line-height: 1;
    vertical-align: middle;
    margin-right: 0.125rem;
  }

  /* ── Lines ── */

  /* Stack of rows. Each row is its own flex container so it can carry a
     background tint (set from the per-block score). The row separator
     and inline padding live on .weather-row. */
  .weather-lines.svelte-x97k5r {
    display: flex;
    flex-direction: column;
  }

  .weather-row.svelte-x97k5r {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.25rem 0.5rem;
    padding: 0.375rem 0.5rem;
    border-radius: 0.375rem;
  }
  .weather-row.svelte-x97k5r + .weather-row:where(.svelte-x97k5r) {
    margin-top: 0.125rem;
    border-top: 1px solid var(--color-slate-200, #e2e8f0);
  }
  /* Tinted rows don't get the inter-row separator line — the tint already
     defines the row boundary visually. */
  .weather-row--low.svelte-x97k5r + .weather-row:where(.svelte-x97k5r),
  .weather-row.svelte-x97k5r + .weather-row--low:where(.svelte-x97k5r),
  .weather-row--very-low.svelte-x97k5r + .weather-row:where(.svelte-x97k5r),
  .weather-row.svelte-x97k5r + .weather-row--very-low:where(.svelte-x97k5r) {
    border-top: none;
  }

  html.dark .weather-row.svelte-x97k5r + .weather-row:where(.svelte-x97k5r) {
    border-top-color: var(--color-slate-700, #334155);
  }

  /* Per-block score tint. Score < 0.65 → light pink; < 0.5 → stronger pink. */
  .weather-row--low.svelte-x97k5r {
    background: #ffeef3; /* very pale rose-pink */
  }
  .weather-row--very-low.svelte-x97k5r {
    background: #fecdd3; /* rose-200 */
    color: #881337; /* rose-900 — strong contrast on the saturated pink */
  }
  html.dark .weather-row--low.svelte-x97k5r {
    background: rgba(244, 63, 94, 0.10);
  }
  html.dark .weather-row--very-low.svelte-x97k5r {
    background: rgba(244, 63, 94, 0.24);
    color: #fecdd3; /* rose-200 — strong contrast on the dark-rose backdrop */
  }

  .weather-sentence.svelte-x97k5r {
    flex: 1 1 0;
    min-width: 0;
  }

  .weather-pills.svelte-x97k5r {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    align-items: center;
    gap: 0.25rem;
    margin-inline-start: auto;
  }

  /* ── Pills ── */

  .weather-pill.svelte-x97k5r {
    display: inline-flex;
    align-items: center;
    gap: 0.125rem;
    padding: 0 0.375rem;
    border-radius: 9999px;
    border: 1px solid var(--color-slate-200, #e2e8f0);
    background: var(--color-slate-50, #f8fafc);
    font-size: 0.75rem;
    font-weight: 500;
    white-space: nowrap;
    line-height: 1.5;
    vertical-align: middle;
    flex-shrink: 0;
  }

  html.dark .weather-pill.svelte-x97k5r {
    border-color: var(--color-slate-600, #475569);
    background: var(--color-slate-800, #1e293b);
    color: var(--color-slate-300, #cbd5e1);
  }

  .wind-pill.svelte-x97k5r {
    color: var(--color-sky-700, #0369a1);
    border-color: var(--color-sky-200, #bae6fd);
    background: var(--color-sky-50, #f0f9ff);
  }

  html.dark .wind-pill.svelte-x97k5r {
    color: var(--color-sky-300, #7dd3fc);
    border-color: var(--color-sky-700, #0369a1);
    background: var(--color-sky-950, #082f49);
  }

  .wave-pill.svelte-x97k5r {
    color: var(--color-teal-700, #0f766e);
    border-color: var(--color-teal-200, #99f6e4);
    background: var(--color-teal-50, #f0fdfa);
  }

  html.dark .wave-pill.svelte-x97k5r {
    color: var(--color-teal-300, #5eead4);
    border-color: var(--color-teal-700, #0f766e);
    background: var(--color-teal-950, #042f2e);
  }

  .wind-arrow.svelte-x97k5r,
  .wave-arrow.svelte-x97k5r {
    font-size: 12px;
    display: inline-block;
    line-height: 1;
    vertical-align: middle;
  }

  .wave-icon.svelte-x97k5r {
    font-size: 12px;
    display: inline-block;
    line-height: 1;
    vertical-align: middle;
  }

  .weather-unavailable.svelte-x97k5r {
    font-size: 0.875rem;
    color: var(--color-slate-400, #94a3b8);
    margin: 0;
  }

  /* Align the Suggest-alternatives button to the inline-end of the card
     (right in LTR, left in RTL). Direction is read from the body content
     via the dir attribute on this row, so an English-locale card aligns
     right and a Hebrew/Arabic card aligns left. */
  .weather-suggest-alts-row.svelte-x97k5r {
    text-align: end;
  }

  .weather-suggest-alts-btn.svelte-x97k5r {
    display: inline-block;
    margin-top: 0.5rem;
    padding: 0.25rem 0.75rem;
    background: #fecdd3; /* rose-200 — matches .weather-row--very-low */
    border: 1px solid #fda4af; /* rose-300 — slight outline for definition */
    border-radius: 1rem;
    font-size: 0.8125rem;
    color: #881337; /* rose-900 — matches .weather-row--very-low text */
    cursor: pointer;
    transition: background 0.15s ease;
  }

  .weather-suggest-alts-btn.svelte-x97k5r:hover {
    background: #fda4af; /* rose-300 */
  }

  html.dark .weather-suggest-alts-btn.svelte-x97k5r {
    background: rgba(244, 63, 94, 0.24);
    border-color: rgba(244, 63, 94, 0.40);
    color: #fecdd3; /* rose-200 */
  }
  html.dark .weather-suggest-alts-btn.svelte-x97k5r:hover {
    background: rgba(244, 63, 94, 0.36);
  }

.itinerary-panel-inner {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
  background-color: white;
}

.itinerary-panel-header {
  display: flex;
  flex-shrink: 0;
  gap: 6px;
  align-items: center;
  justify-content: space-between;
  padding: 10px;
}

.itinerary-title {
  min-width: 0;
  overflow: hidden;
  font-size: 18px;
  font-weight: 500;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.itinerary-actions-wrapper {
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: flex-end;
}

.itinerary-actions {
  display: flex;
  gap: 8px;
}

.itinerary-undo-redo {
  display: flex;
  gap: 8px;
}

/* When the undo/redo group rides the length-line row (item 12 layout):
   - reset the icon color so it doesn't inherit the row's muted 60%-black text;
   - the 16px inline-start margin (matching the header's column gap) pushes the
     locale pill 16px left so its right edge lines up with the title field's
     right edge, while the group itself stays aligned under Discard/Done.

   U19 (R26) added the cover-picture button to this group as its FIRST child,
   which is what puts it between the locale control and undo. The group is now
   three buttons wide, so it starts 32px further left; nothing here needed to
   change for that (the auto-margin on the pill absorbs it), but the row is the
   first thing to check if the header ever starts wrapping on a narrow panel. */
.itinerary-total-distance .itinerary-undo-redo {
  margin-inline-start: 16px;
  color: rgb(0 0 0 / 87%);
}

/* U19 (R27) — the inline discard failure, under the action buttons it belongs
   to. `.itinerary-actions-wrapper` is a right-aligned column, so this sits
   directly beneath Discard/Done; `text-align: end` keeps a wrapped second line
   ragged on the same side. */
.itinerary-discard-error {
  max-width: 220px;
  font-size: 12px;
  line-height: 1.3;
  color: #c62828;
  text-align: end;
}

.itinerary-button {
  padding: 8px 16px;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  background-color: #f0f0f0;
  border: none;
  border-radius: 20px;
  transition: background-color 0.2s;
}

.itinerary-button:hover {
  background-color: #e0e0e0;
}

.itinerary-icon-button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  min-width: 32px;
  height: 32px;
  min-height: 32px;
  cursor: pointer;
  background-color: #f0f0f0;
  border: none;
  border-radius: 50%;
  transition: background-color 0.2s;
}

.itinerary-icon-button:hover:not(:disabled) {
  background-color: #e0e0e0;
}

.itinerary-icon-button:disabled {
  cursor: default;
  opacity: 0.4;
}

.itinerary-icon-button.save-button {
  color: white;
  background-color: #4caf50;
}

.itinerary-icon-button.save-button:hover {
  background-color: #45a049;
}

.itinerary-icon-button .material-symbols-outlined {
  font-size: 20px;
}

.itinerary-title-container {
  flex: 1;
  min-width: 0;
}

.itinerary-total-distance {
  display: flex;
  gap: 4px;
  align-items: center;

  /* F1 — explicit `width: 100%` so the flex row fills its grid cell
     (`.details-header { grid-template-columns: minmax(0, 1fr) auto }`).
     Without it the row collapsed to content width and the LocalePill's
     `margin-inline-start: auto` had no free space to consume, pinning the
     pill next to the "X days • Y nm" text instead of the row's logical-end
     edge. RTL-safe — auto-margin flips with direction. */
  width: 100%;
  font-size: 14px;
  color: rgb(1 1 1 / 60%);
}

.itinerary-close-button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  min-width: 32px;
  height: 32px;
  min-height: 32px;
  cursor: pointer;
  background: #f0f0f0;
  border: none;
  border-radius: 50%;
}

.create-itinerary-row {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: 8px 16px;
  cursor: pointer;
  background-color: #0369a1;
  border: none;
  border-bottom: 1px solid #075985;
}

.create-itinerary-row .create-itinerary-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 7px 20px;
  font-size: 14px;
  font-weight: 600;
  color: #0369a1;
  background-color: white;
  border-radius: 9999px;
  transition: background-color 0.15s;
}

.create-itinerary-row:hover .create-itinerary-pill {
  background-color: #e0f2fe;
}

.itinerary-separator {
  height: 1px;
  background-color: #cacaca;
}

.itinerary-panel-body {
  flex-grow: 1;
  height: 100%;
  padding: 12px;
  padding-bottom: 80px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.itineraries-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
}

.itinerary-item {
  position: relative;
  height: 150px;
  overflow: hidden;
  cursor: pointer;
  border: 2px solid transparent;
  border-radius: 15px;
}

/* U3 (pre-launch fixes) — like button overlay on each My-tab tile. Sits in
   the top-right corner over the cover photo; the wrapper stops click
   propagation so the underlying tile's "open details" handler doesn't fire. */
.itinerary-item-like {
  position: absolute;
  top: 6px;
  right: 6px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  cursor: pointer;
  background: rgb(255 255 255 / 75%);
  backdrop-filter: blur(2px);
  border-radius: 999px;
  box-shadow: 0 1px 3px rgb(0 0 0 / 15%);
}

.itinerary-item-like :global(.like-itinerary-button) {
  padding: 0;
}

.itinerary-item-like :global(.like-itinerary-button .material-symbols-outlined) {
  font-size: 22px;
}

.itinerary-item.selected {
  border-color: #007bff;

  &::before {
    position: absolute;
    inset: -2px;
    pointer-events: none;
    content: "";
    background: rgb(255 255 255 / 50%);
  }

  .itinerary-view-on-map {
  }

  .itinerary-item-title {
    color: black;
    text-shadow: none;

    .arrow-icon {
      /* visibility: visible; */
    }

    .itinerary-pill {
      color: white;
    }
  }
}

.itinerary-item.selected::after {
  position: absolute;
  inset: 0;
  pointer-events: none;
  content: "";
  background-color: rgb(0 123 255 / 10%);
  border-radius: 13px;
}

.itinerary-item.previewing {
  border-color: #7c7cbb;

  &::before {
    position: absolute;
    inset: -2px;
    pointer-events: none;
    content: "";
    background: rgb(255 255 255 / 50%);
  }

  .itinerary-item-title {
    color: black;
    text-shadow: none;

    .itinerary-pill {
      color: white;
    }
  }
}

.itinerary-item.previewing::after {
  position: absolute;
  inset: 0;
  pointer-events: none;
  content: "";
  background-color: rgb(124 124 187 / 10%);
  border-radius: 13px;
}

.itinerary-item.deselecting {
  animation: deselect 1.5s ease-out forwards;
}

.itinerary-item.deselecting::before {
  position: absolute;
  inset: -2px;
  pointer-events: none;
  content: "";
  animation: deselect-before 1.5s ease-out forwards;
}

.itinerary-item.deselecting::after {
  position: absolute;
  inset: 0;
  pointer-events: none;
  content: "";
  border-radius: 13px;
  animation: deselect-overlay 1.5s ease-out forwards;
}

@keyframes deselect {
  0% {
    border-color: #007bff;
    transform: scale(1.02);
  }

  10% {
    border-color: #007bff;
    transform: scale(1);
  }

  100% {
    border-color: transparent;
    transform: scale(1);
  }
}

@keyframes deselect-before {
  0%,
  10% {
    background: rgb(255 255 255 / 50%);
  }

  100% {
    background: transparent;
  }
}

@keyframes deselect-overlay {
  0%,
  10% {
    background-color: rgb(0 123 255 / 10%);
  }

  100% {
    background-color: transparent;
  }
}

.itinerary-item img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.itinerary-item-title {
  position: absolute;
  top: 10px;
  right: 10px;
  left: 10px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: space-between;
  padding: 5px 40px 5px 5px;
  font-size: 1.2em;
  font-weight: bold;
  color: white;
  text-shadow: 1px 1px 7px rgb(0 0 0 / 90%);
  border-radius: 5px;

  /* background: rgba(0, 0, 0, 0.5); */

  /* width: calc(100%); */
}

.itinerary-meta-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 2px;
}

.itinerary-pill {
  display: inline-flex;
  gap: 4px;
  align-items: center;
  padding: 2px 8px;
  font-size: 12px;
  font-weight: 500;
  text-shadow: none;
  background: rgb(0 0 0 / 50%);
  border-radius: 9999px;
}

.itinerary-pill .material-symbols-outlined {
  font-size: 14px;
}

/* U12 — action row hosting the fixed-function 'View on map' / 'View details'
   buttons. flex-wrap plus non-shrinking buttons make the pair wrap to a
   second line at narrow tile widths instead of shrinking below usable touch
   targets or overflowing the tile. */
.itinerary-tile-actions {
  position: absolute;
  right: 10px;
  bottom: 10px;
  left: 10px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.itinerary-view-on-map {
  display: flex;
  flex: none;
  gap: 4px;
  align-items: center;
  min-width: 44px;
  padding: 8px;
  font-size: 14px;
  font-weight: 400;
  color: white;
  white-space: nowrap;
  background: rgb(0 0 0 / 50%);
  border-radius: 5px;
}

.itinerary-view-on-map span {
  font-size: 18px;
}

.itinerary-card-actions {
  position: absolute;
  bottom: 10px;
  left: 10px;
  display: flex;
  gap: 6px;
}

.itinerary-preview-btn,
.itinerary-add-btn {
  display: flex;
  gap: 4px;
  align-items: center;
  padding: 6px 10px;
  font-size: 13px;
  font-weight: 400;
  color: white;
  cursor: pointer;
  background: rgb(0 0 0 / 50%);
  border: none;
  border-radius: 5px;
}

.itinerary-preview-btn span,
.itinerary-add-btn span {
  font-size: 16px;
}

.itinerary-item.previewing .itinerary-preview-btn {
  background: rgb(124 124 187 / 80%);
}

.arrow-icon {
  position: absolute;
  top: 18px;
  right: 10px;
  font-size: 1em;
  font-size: 24px;
  font-weight: 400;
  color: white;
  visibility: hidden;
}

.itinerary-panel-inner {
  overflow: hidden; /* To contain the sliding panel */
}

.itinerary-list-view {
  height: 100%;
  transition: transform 0.1s ease-in-out;
  transform: translateX(0);

  &.hide {
    transition: transform 0.3s ease-in-out;
    transform: translateX(-20px);
  }
}

.itinerary-details-view {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 10;
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  overflow-y: auto;
  background-color: white;
  transition: transform 0.3s ease-in-out;
  transform: translateX(100%);
}

.itinerary-details-view.show {
  transform: translateX(0);
}

.itinerary-details-view .itinerary-panel-body {
  padding-top: 0;
}

.details-header {
  position: sticky;
  top: 0;
  z-index: 100;

  /* Override .itinerary-panel-header's flex layout in favor of grid so we can
     place A/B/C into named areas (Panel A = title-and-like, Panel B =
     total-distance, Panel C = actions-wrapper).
     F1 follow-up: stats spans both columns so the LocalePill at the end of
     the stats row (via `margin-inline-start: auto`) reaches the panel's
     right edge instead of stopping at the title-column boundary. Actions
     collapses to row 1 only — visually equivalent because the buttons were
     already top-aligned via `align-self: center` in a taller-row span. */
  display: grid;
  grid-template-areas:
    "title    actions"
    "stats    stats";
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 4px 16px;
  align-items: center;
  background-color: white;

  /* Container-query basis for the narrow-layout switch below. CSS cannot
     detect "exactly when A would wrap/clip" without JS — we approximate
     with a width threshold tuned to typical title widths. */
  container-type: inline-size;
}

/* The title-container is a structural wrapper around A+B in the markup. To
   let A and B participate in the .details-header grid as siblings of C
   (instead of being nested under a single grid cell), unwrap it via
   display: contents. The .itinerary-title-container rule at the top of
   this file (line 106) still applies in non-details-header contexts (e.g.
   ItineraryDetailsShimmer.svelte has its own scoped rule). */
.details-header .itinerary-title-container {
  display: contents;
}

.details-header .itinerary-title-and-like {
  grid-area: title;
  align-self: end;
}

/* Editing mode renders a contenteditable div directly inside the
   display:contents wrapper. Give it an explicit grid-area so it
   doesn't rely on auto-placement. */
.details-header .itinerary-title-input {
  grid-area: title;
  align-self: end;
}

.details-header .itinerary-total-distance {
  grid-area: stats;
  align-self: start;
}

.details-header .itinerary-actions-wrapper {
  grid-area: actions;
  align-self: center;
}

/* Narrow panel: switch to Option 2 — A spans the full first row, B and C
   share the second row (B left, C right). Threshold is empirical, not
   tied to A's actual clip; if titles regularly clip above this width,
   raise the threshold. */
@container (max-width: 380px) {
  .details-header {
    grid-template-areas:
      "title    title"
      "stats    actions";
  }

  .details-header .itinerary-actions-wrapper {
    place-self: start end;
  }
}

/* Fallback for browsers without @container support (Safari <16, Firefox <110).
   Use a viewport-width proxy (480px > 380px container to account for panel
   being narrower than the viewport). */
@supports not (container-type: inline-size) {
  @media (width <= 480px) {
    .details-header {
      grid-template-areas:
        "title    title"
        "stats    actions";
    }

    .details-header .itinerary-actions-wrapper {
      place-self: start end;
    }
  }
}

.details-header .itinerary-title {
  overflow: visible;
  text-overflow: unset;
  white-space: normal;
}

.itinerary-title-and-like {
  display: flex;
  gap: 4px;
  align-items: flex-start;
}

.itinerary-title-like {
  flex-shrink: 0;
  padding: 0;
}

.itinerary-title-like .material-symbols-outlined {
  font-size: 18px;
}

.itinerary-steps {
  padding: 0;
}

.step {
  position: relative;
  display: flex;
  align-items: flex-start;
  padding: 8px 8px 8px 0;
  margin: 0;
  cursor: pointer;
  user-select: none;
  border-radius: 12px;
}

.step.selected {
  background-color: transparent;

  .step-title-container {
    button {
      visibility: visible;
    }
  }
}

/* Always visible (it used to fade in on row hover) and a single eye icon —
   the chevron is gone. */
.step-detail-indicator {
  display: flex;
  align-items: center;
  color: #666;
  cursor: pointer;

  .material-symbols-outlined {
    font-size: 18px;
  }

  &:hover {
    color: #333;
  }
}

.step-icon-container {
  position: relative;
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  align-items: center;
  align-self: stretch;
  min-width: 36px;
  margin-right: 6px;
}

.step-poi-name {
  padding-top: 4px;
  padding-bottom: 6px;
  font-size: 14px;
  font-weight: 500;
  color: #333;
}

.step-line {
  position: relative;
  flex-grow: 1;
  width: 3px;
  border-radius: 2px;

  .step-distance {
    position: absolute;
    top: 50%;
    left: 50%;
    padding: 2px 6px;
    font-size: 10px;
    color: #9e9e9e;
    background: white;
    transform: translate(-50%, -50%);
  }
}

.step-icon {
  position: relative;
  display: flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  background: transparent;
  border-radius: 50%;

  .material-symbols-outlined {
    font-size: 22px;
    color: inherit;
  }

  img.poi-icon {
    width: 28px;
    height: 28px;
  }
}

.step-content {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  gap: 6px;
  justify-content: center;
  min-height: 32px;
}

.step-title-container {
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: space-between;

  .step-title {
    font-weight: bold;
  }

  button {
    visibility: hidden;
    background: transparent;
  }
}

.itinerary-details-view.is-editing
  .step-title-container
  span
  button.delete-button,
.itinerary-details-view.is-editing
  .step-title-container
  span
  button.edit-button {
  visibility: visible;
}

.step-poi-row {
  display: flex;
  gap: 10px;
  align-items: center;
  width: 100%;
}

.step-poi-name {
  flex: 1;
  font-size: 14px;
  font-weight: 500;
  color: #333;
}

.step-actions {
  display: flex;
  gap: 4px;
  margin-left: auto;
}

.step-text {
  min-height: 18px;
  padding: 6px 10px;
  font-size: 13px;
  color: #333;
  user-select: text;
  border: 1px dashed #ccc;
  border-radius: 6px;
}

.step-text-placeholder:empty::before {
  font-style: italic;
  color: #aaa;
  content: attr(data-placeholder);
}

/* Mobile landscape - reduce bottom padding to allow scrolling to last item */
@media (height <= 500px) and (orientation: landscape) {
  .itinerary-panel-body {
    padding-bottom: 20px;
  }
}

/* In-place editor styles */
.step-text[contenteditable="true"] {
  min-height: 1.2em;
  padding: 4px;
  cursor: text;
  border: 1px dashed #ccc;
  border-radius: 4px;
  outline: none;
  transition:
    border-color 0.2s,
    background-color 0.2s;
}

.step-text[contenteditable="true"]:hover {
  background-color: #fafafa;
  border-color: #bbb;
}

.step-text[contenteditable="true"]:focus {
  background-color: white;
  border-color: #2196f3;
  box-shadow: 0 0 0 2px rgb(33 150 243 / 10%);
}

.itinerary-title-input {
  width: 100%;
  min-height: 1.2em;
  padding: 4px;
  margin: -4px;
  font-family: inherit;
  color: inherit;
  word-break: break-word;
  background: transparent;
  border: 1px dashed #ccc;
  border-radius: 4px;
  outline: none;
}

.itinerary-title-input:focus {
   background: white;
   border-color: #2196f3;
}

.drag-handle {
	display: flex;
	align-items: center;
	justify-content: center;
	margin-bottom: 4px;
	color: #bdbdbd;
	cursor: grab;
}

.drag-handle .material-symbols-outlined {
	font-size: 20px;
}

.drop-indicator {
  position: relative;
  z-index: 10;
  height: 2px;
  margin: -1px 0;
  pointer-events: none;
  background-color: #2196f3;
}

.drop-indicator::before {
  position: absolute;
  top: 50%;
  left: 0;
  width: 6px;
  height: 6px;
  content: '';
  background-color: #2196f3;
  border-radius: 50%;
  transform: translateY(-50%);
}

.proposal-alert {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 16px;
  margin: 12px 0;
  border-radius: 12px;
  animation: slideDown 0.3s ease-out;
}

.proposal-alert .material-symbols-outlined {
  font-size: 24px;
  color: #2196f3;
}

.proposal-content {
  flex: 1;
}

.proposal-text {
  margin-bottom: 8px;
  font-size: 14px;
  color: #333;
}

.proposal-actions {
  display: flex;
  gap: 8px;
}

.proposal-actions button {
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  border-radius: 6px;
  transition: opacity 0.2s;
}

.proposal-actions button:hover {
  opacity: 0.8;
}

.accept-button {
  color: white;
  background-color: #2196f3;
  border: none;
}

.ignore-button {
  color: #666;
  background-color: transparent;
  border: 1px solid #ccc;
}

.reorder-proposal {
  border: 1px solid #2196f3;
}

.proposal-alert.compact {
  padding: 8px 12px;
  margin: 4px 0 4px 42px;
  font-size: 13px;
  background-color: rgb(33 150 243 / 5%);
  border-style: dashed;
  box-shadow: none;

  .material-symbols-outlined {
    font-size: 20px;
  }

  .proposal-card-content {
      margin-bottom: 4px;
  }

  .proposal-actions button {
      padding: 4px 8px;
      font-size: 12px;
  }
}

.step.suggested-source {
    border: 1px dashed #2196f3;
    animation: pulseSubtle 2s infinite ease-in-out;
}

.step.suggestion-highlight {
    background-color: rgb(33 150 243 / 10%);
    border: 2px dashed #2196f3;
    animation: pulseHighlight 1.5s infinite ease-in-out;
}

@keyframes pulseHighlight {
    0% { background-color: rgb(33 150 243 / 10%); }
    50% { background-color: rgb(33 150 243 / 20%); }
    100% { background-color: rgb(33 150 243 / 10%); }
}

.poi-move-suggestion-wrapper {
    margin: 4px 0 4px 42px;
}

.poi-delete-suggestion-wrapper {
    margin: 4px 0 4px 42px;
}

@keyframes pulseSubtle {
    0% { background-color: transparent; }
    50% { background-color: rgb(33 150 243 / 5%); }
    100% { background-color: transparent; }
}

.search-start-point-message {
  display: flex;
  gap: 12px;
  align-items: center;
  justify-content: center;
  padding: 24px 16px;
  margin: 16px;
  font-size: 16px;
  color: #666;
  background-color: #f5f5f5;
  border: 2px dashed #ccc;
  border-radius: 12px;
}

.search-start-point-message .material-symbols-outlined {
  font-size: 28px;
  color: #2196f3;
}

.start-at-plan-marina-link {
  padding: 0;
  font-size: inherit;
  color: #0369a1;
  text-decoration: underline;
  cursor: pointer;
  background: none;
  border: none;
}

.start-at-plan-marina-link:hover {
  color: #075985;
}

/* Nav-point start point: coordinates line + day-break affordance under the
   "Starting point selected" message. */
.start-point-coords {
  margin: -8px 16px 0;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  color: #666;
  text-align: center;
  letter-spacing: 0.02em;
}

.start-point-daybreak {
  display: flex;
  justify-content: center;
  margin: 8px 16px 0;
}

.start-point-daybreak-note {
  margin: 8px 16px 0;
  font-size: 13px;
  color: #666;
  text-align: center;
}

.change-start-button {
  padding: 6px 16px;
  font-size: 14px;
  color: #fff;
  cursor: pointer;
  background-color: #2196f3;
  border: none;
  border-radius: 20px;
  transition: background-color 0.2s;
}

.change-start-button:hover {
  background-color: #1976d2;
}

button.search-mode-active {
  color: white !important;
  background-color: #1565c0 !important;
  box-shadow: inset 0 2px 4px rgb(0 0 0 / 40%) !important;
  transform: scale(0.95) !important;
}

button.search-mode-active:hover {
  background-color: #1565c0 !important;
  transform: scale(0.95) !important;
}

.itinerary-day-group {
    margin: 6px 0;
    overflow: hidden;
    border: 1px solid;
    border-radius: 12px;
    box-shadow: 0 1px 3px rgb(0 0 0 / 4%);
}

.itinerary-day-header {
    display: flex;
    gap: 8px;
    align-items: flex-start;
    padding: 12px;
    cursor: pointer;
    user-select: none;
    background-color: transparent;
}

/* The day disclosure toggle — a real <button> (keyboard + aria-expanded)
   reset to render exactly like the bare chevron span it replaced. */
.day-toggle-button {
    display: flex;
    padding: 0;
    margin: 0;
    cursor: pointer;
    background: none;
    border: none;
}

.itinerary-day-header .material-symbols-outlined {
    margin-top: 2px;
    font-size: 24px;
    color: #9e9e9e;
    transition: transform 0.2s ease;
}

.itinerary-day-group.day-open > .itinerary-day-header .material-symbols-outlined {
    transform: rotate(90deg);
}

/* Collapsed day: hide the content region (was <details>'s native behavior;
   kept in the DOM so aria-controls resolves and weather stays warm). */
.itinerary-day-group:not(.day-open) > .itinerary-day-content {
    display: none;
}

.itinerary-day-title {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 2px;
    overflow: hidden;
}

.day-number {
    font-size: 14px;
    font-weight: 600;
    white-space: nowrap;
}

.day-label {
    font-size: 14px;
    font-weight: 500;
    color: #333;
}

.day-label-input {
    min-width: 100px;
    padding: 2px 4px;
    margin: -2px -4px;
    cursor: text;
    border: 1px dashed transparent;
    border-radius: 4px;
    outline: none;
}

.day-label-input:hover {
    border-color: #ccc;
}

.day-label-input:focus {
    background: white;
    border-color: #666;
    border-style: solid;
}

.day-label-input:empty::before {
    color: #999;
    pointer-events: none;
    content: attr(data-placeholder);
}

.day-sail-length {
    margin-top: 2px;
    font-size: 13px;
    font-weight: 400;
    color: #757575;
    white-space: nowrap;
}

/* Same stroke as the step-tile icons (18px, #666), and the box rides the
   distance label's line so the icon centers on it (the header is
   flex-start-aligned). */
.day-delete-button {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0 4px;
    margin-top: 2px;
    color: #666;
    cursor: pointer;
    background: none;
    border: none;
    border-radius: 4px;
    transition: background-color 0.2s ease;
}

.day-delete-button:hover {
    color: #f44336;
    background-color: rgb(244 67 54 / 10%);
}

/* color: inherit beats the header's own icon-color rule, so the button's
   #666 (and its red hover) actually reach the glyph. */
.day-delete-button .material-symbols-outlined {
    margin-top: 0;
    font-size: 18px;
    color: inherit;
    transform: none !important;
}

.itinerary-day-content {
    padding: 4px 8px 12px;
}

.day-dragging {
  border: 1px dashed #2196f3;
  opacity: 0.5;
}

.itinerary-days-controls {
    position: sticky;
    top: 0;
    z-index: 5;
    display: flex;
    gap: 8px;
    justify-content: flex-end;
    padding: 4px 0;
    margin-bottom: 8px;
    background: white;
}

.days-toggle-button {
    display: flex;
    gap: 4px;
    align-items: center;
    padding: 4px 10px;
    font-size: 12px;
    font-weight: 500;
    color: #666;
    cursor: pointer;
    background: #f5f5f5;
    border: 1px solid #e0e0e0;
    border-radius: 16px;
    transition: background-color 0.2s, border-color 0.2s;
}

.days-toggle-button:hover {
    color: #333;
    background: #ebebeb;
    border-color: #ccc;
}

.days-toggle-button .material-symbols-outlined {
    font-size: 16px;
}

.step-description {
    margin-top: 2px;
    font-size: 12px;
    line-height: 1.4;
    color: #757575;
}

.step-actions {
    display: flex;
    gap: 8px;
    margin-top: 8px;
}

.step-action-button {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 4px;
    color: #999;
    cursor: pointer;
    background: transparent;
    border: none;
    border-radius: 4px;
    transition: background-color 0.2s, color 0.2s;
}

.step-action-button:hover {
    color: #333;
    background-color: #f5f5f5;
}

.step-action-button.delete:hover {
    color: #f44336;
    background-color: #feebeb;
}

/* The delete and split icons match the eye (.step-detail-indicator): same
   #666 stroke and the same 18px size — the 24px default reads as a wider
   stroke next to it. */
.step-action-button.delete {
    color: #666;
}

.step-action-button.split-day {
    gap: 2px;
    padding: 2px 6px 2px 4px;
    color: #666;
}

.step-action-button.delete .material-symbols-outlined,
.step-action-button.split-day .material-symbols-outlined {
    font-size: 18px;
}

.split-day-label {
    font-size: 11px;
    white-space: nowrap;
}

/* Batch 7 — per-haven "Add" suggestions menu */
.haven-add-wrapper {
  position: relative;
  display: flex;
}

.step-action-button.haven-add-trigger {
  gap: 0;
  padding: 2px 2px 2px 8px;
  color: #0369a1;
}

.step-action-button.haven-add-trigger:hover {
  color: #075985;
  background-color: #e8f4fb;
}

/* Step-tile action arrangement (see stepTileLayout). One row beside a
   non-wrapping name in the order split, add, delete, eye; when the name
   needs the width the row becomes a 2×2 grid — split+eye on top,
   add+delete below — expressed purely via `order`. */
.step-actions .split-day {
  order: 1;
}

.step-actions .haven-add-wrapper {
  order: 2;
}

.step-actions .delete {
  order: 3;
}

.step-actions .step-detail-indicator {
  order: 4;
}

.step-poi-row.actions-2x2 {
  align-items: flex-start;
}

/* The name's first line centers on the first button row: stepTileLayout
   computes (row1 height − line height) / 2 as top padding, so the first
   line box's center meets the row's center and wrapped lines continue
   below. */
.step-poi-row.actions-2x2 .step-poi-name {
  padding-top: var(--step-name-align-pad, 4px);
}

.step-poi-row.actions-2x2 .step-actions {
  display: grid;
  grid-template-columns: auto auto;
  justify-items: start;
  margin-top: var(--step-actions-align-pad, 0);
}

/* Explicit cells rather than auto-flow: whichever buttons a tile has, the
   eye and delete keep the second column (centered in it, so the delete
   sits horizontally centered under the eye), split and add the first. */
.step-poi-row.actions-2x2 .step-actions .split-day {
  grid-area: 1 / 1;
}

.step-poi-row.actions-2x2 .step-actions .step-detail-indicator {
  grid-area: 1 / 2;
  justify-self: center;
}

.step-poi-row.actions-2x2 .step-actions .haven-add-wrapper {
  grid-area: 2 / 1;
}

/* View mode has no split/delete: the nearby menu takes row 1 beside the eye
   instead of leaving that cell empty. */
.step-poi-row.actions-2x2 .step-actions .haven-add-wrapper.view-mode {
  grid-area: 1 / 1;
}

.step-poi-row.actions-2x2 .step-actions .delete {
  grid-area: 2 / 2;
  justify-self: center;
}

.haven-add-label {
  font-size: 11px;
  white-space: nowrap;
}

.haven-add-caret {
  font-size: 18px;
}

/* Portaled to <body> (the panel's transform hijacks position:fixed), so
   these stack at root level: above the slide panel (z-index 1000), below
   full-screen modals (9999). */
.haven-add-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1100;
}

.haven-add-menu {
  position: fixed;
  z-index: 1101;
  display: flex;
  flex-direction: column;

  /* The min() keeps min-width from beating the on-screen width clamp on
     viewports narrower than 256px — CSS resolves min>max in min's favor. */
  min-width: min(240px, calc(100vw - 16px));
  max-width: 300px;
  padding: 4px 0;
  overflow-y: auto;
  background: white;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  box-shadow: 0 4px 16px rgb(0 0 0 / 15%);
}

.haven-add-section-title {
  padding: 6px 12px 2px;
  font-size: 11px;
  font-weight: 600;
  color: #888;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.haven-add-separator {
  height: 1px;
  margin: 4px 0;
  background-color: #e0e0e0;
}

.haven-add-item {
  display: flex;
  gap: 8px;
  align-items: center;
  width: 100%;
  padding: 7px 12px;
  font-size: 13px;
  color: #333;
  text-align: left;
  cursor: pointer;
  background: transparent;
  border: none;
}

.haven-add-item:hover {
  background-color: #f5f5f5;
}

/* Suggestion entry: the add button plus a trailing eye that opens the POI
   details. Two sibling buttons (a button can't nest a button) laid out as
   one visual row. */
.haven-add-row {
  display: flex;
  align-items: stretch;
}

.haven-add-row:hover {
  background-color: #f5f5f5;
}

.haven-add-row .haven-add-item {
  min-width: 0;
}

.haven-add-eye {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  padding: 0 12px 0 2px;
  color: #94a3b8;
  cursor: pointer;
  background: transparent;
  border: none;
}

.haven-add-eye:hover {
  color: #0369a1;
}

.haven-add-eye .material-symbols-outlined {
  font-size: 18px;
}

/* Suggestion rows carry the POI-type <img> icon; the set-prefs row still
   uses a font symbol, which the font-size/color serve. */
.haven-add-item-icon {
  flex-shrink: 0;
  font-size: 18px;
  color: #666;
}

img.haven-add-item-icon {
  width: 18px;
  height: 18px;
}

.haven-add-item-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.haven-add-item-dist {
  flex-shrink: 0;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: #999;
}

.haven-add-set-prefs .haven-add-item-name {
  color: #0369a1;
  white-space: normal;
}

/* This section intentionally left empty - styles consolidated above */

/* Drag and drop for day groups */
.itinerary-day-group.day-dragging {
  opacity: 0.5;
}

/* Insertion line between days during drag */
.day-drop-indicator {
  position: relative;
  z-index: 10;
  height: 2px;
  margin: -1px 0;
  pointer-events: none;
  background-color: #2196f3;
}

.day-drop-indicator::before {
  position: absolute;
  top: 50%;
  left: 0;
  width: 6px;
  height: 6px;
  content: '';
  background-color: #2196f3;
  border-radius: 50%;
  transform: translateY(-50%);
}

/* Visual feedback when day is about to expand on drag hover */
.itinerary-day-group.day-expand-pending > .itinerary-day-header {
  background-color: rgb(33 150 243 / 8%);
  transition: background-color 0.2s ease;
}

/* Diagonal cross over icon (for remove day break button) */
.icon-crossed {
  position: relative;
}

.icon-crossed::after {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 120%;
  height: 2px;
  content: '';
  background-color: currentcolor;
  border-radius: 1px;
  transform: translate(-50%, -50%) rotate(-45deg);
}

/* Start point styling (previous day's end point shown at day start) */
.step.start-point {
  opacity: 0.6;
}

.step.start-point .step-icon-container {
  flex-direction: column-reverse;
}

.step.start-point .step-line {
  flex-grow: 0;
  height: 16px;
}

.start-point-label {
  padding: 2px 6px;
  font-size: 11px;
  color: #9e9e9e;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  background: #f5f5f5;
  border-radius: 4px;
}

/* Toggle between Suggested and My Itineraries */
.itinerary-mode-toggle {
  display: flex;
  gap: 2px;
  padding: 3px;
  background-color: #f0f0f0;
  border-radius: 20px;
}

.toggle-btn {
  /* Positioning context for the divider below. */
  position: relative;
  padding: 4px 8px;
  font-size: 11px;
  font-weight: 500;
  color: #666;
  cursor: pointer;
  background-color: transparent;
  border: none;
  border-radius: 16px;
  transition: all 0.2s ease;
}

/* A hairline between adjacent tabs.
   The filled pill marks the ACTIVE tab, which means it separates nothing when
   the two tabs beside each other are both inactive: "My  Shared with crew" ran
   together as one line of grey text with only a 2px gap between two labels that
   are themselves multi-word. The rule is `+ .toggle-btn`, so the first tab
   never draws one — a line at the strip's inner edge would read as a border. */
.toggle-btn + .toggle-btn::before {
  /* `left` is centred in `.itinerary-mode-toggle`'s 2px gap. */
  position: absolute;
  top: 50%;
  left: -1px;
  width: 1px;
  height: 12px;
  content: '';
  background-color: #d0d0d0;
  transform: translateY(-50%);
}

/* Suppressed on both sides of the active pill: its shape already does the
   separating there, and a line touching its rounded edge reads as a rendering
   artefact rather than a divider. */
.toggle-btn.active::before,
.toggle-btn.active + .toggle-btn::before {
  content: none;
}

.toggle-btn:hover {
  color: #333;
}

.toggle-btn.active {
  color: white;
  background-color: #2196f3;
}

/* Share Modal */
.share-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: rgb(0 0 0 / 50%);
}

.share-modal {
  width: 90%;
  max-width: 480px;
  background: white;
  border-radius: 16px;
  box-shadow: 0 4px 24px rgb(0 0 0 / 20%);
}

.share-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid #e0e0e0;
}

.share-modal-header h3 {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
}

.share-modal-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  cursor: pointer;
  background: none;
  border: none;
  border-radius: 50%;
  transition: background-color 0.2s;
}

.share-modal-close:hover {
  background-color: #f0f0f0;
}

.share-modal-body {
  padding: 20px;
}

.share-modal-body p {
  margin: 0 0 16px;
  font-size: 14px;
  color: #666;
}

.share-url-container {
  display: flex;
  gap: 8px;
}

.share-url-input {
  flex: 1;
  padding: 10px 12px;
  font-size: 14px;
  color: #333;
  background-color: #f5f5f5;
  border: 1px solid #e0e0e0;
  border-radius: 8px;
  outline: none;
}

.share-url-input:focus {
  border-color: #2196f3;
}

.share-copy-button {
  display: flex;
  gap: 4px;
  align-items: center;
  padding: 10px 16px;
  font-size: 14px;
  font-weight: 500;
  color: white;
  cursor: pointer;
  background-color: #2196f3;
  border: none;
  border-radius: 8px;
  transition: background-color 0.2s;
}

.share-copy-button:hover {
  background-color: #1976d2;
}

.share-copy-button .material-symbols-outlined {
  font-size: 18px;
}

/* Share Menu Dropdown */
.share-menu-container {
  position: relative;
}

.share-menu-dropdown {
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 100;
  min-width: 220px;
  margin-top: 8px;
  overflow: hidden;
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 20px rgb(0 0 0 / 15%);
}

.share-menu-item {
  display: flex;
  gap: 12px;
  align-items: center;
  width: 100%;
  padding: 14px 16px;
  font-size: 14px;
  font-weight: 500;
  color: #333;
  text-align: left;
  cursor: pointer;
  background: none;
  border: none;
  transition: background-color 0.2s;
}

.share-menu-item:hover {
  background-color: #f5f5f5;
}

.share-menu-item:not(:last-child) {
  border-bottom: 1px solid #e8e8e8;
}

.share-menu-item .material-symbols-outlined {
  font-size: 20px;
  color: #666;
}

.share-menu-backdrop {
  position: fixed;
  inset: 0;
  z-index: 99;
  cursor: default;
  background: transparent;
  border: none;
}

.share-menu-item:disabled {
  cursor: default;
  opacity: 0.7;
}

.share-menu-item:disabled:hover {
  background-color: transparent;
}

/* U2 (pre-launch fixes) — visible help text under the "Add to plan" label
   when the user is signed in but not authorized (not the Skipper and not
   TEAM/ADMIN). The hint sits in a column with the label. */
.share-menu-item-text {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 2px;
}

.share-menu-item-label {
  line-height: 1.3;
}

.share-menu-item-hint {
  font-size: 12px;
  font-weight: 400;
  line-height: 1.3;
  color: #777;
}

/* U2 — "blocked" disabled state (vs. the neutral in-flight disabled).
   Used when the user lacks permission to add the itinerary to the plan. */
.share-menu-item-blocked,
.share-menu-item-blocked:hover {
  color: #777;
  cursor: not-allowed;
  background-color: transparent;
}

.share-menu-item-blocked .material-symbols-outlined {
  color: #999;
}

.share-menu-section {
  padding: 12px 16px;
}

.share-menu-section-title {
  margin-bottom: 4px;
  font-size: 12px;
  font-weight: 600;
  color: #666;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.share-menu-section-subtitle {
  margin-bottom: 12px;
  font-size: 12px;
  line-height: 1.4;
  color: #888;
}

.share-menu-loading,
.share-menu-empty {
  padding: 8px 0;
  font-size: 13px;
  color: #888;
}

.share-menu-bookings {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 200px;
  overflow-y: auto;
}

.share-menu-booking-item {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 8px;
  cursor: pointer;
  border-radius: 8px;
  transition: background-color 0.15s;
}

.share-menu-booking-item:hover {
  background-color: #f5f5f5;
}

.share-menu-booking-item input[type="checkbox"] {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  margin-top: 2px;
  accent-color: #4caf50;
  cursor: pointer;
}

.share-menu-booking-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.share-menu-booking-yacht {
  overflow: hidden;
  font-size: 14px;
  font-weight: 500;
  color: #333;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.share-menu-booking-dates {
  font-size: 12px;
  color: #666;
}

.share-menu-divider {
  height: 1px;
  margin: 0;
  background-color: #e8e8e8;
}

/* Share menu toggle item (for isDemo toggle) */
.share-menu-toggle-item {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 8px;
  cursor: pointer;
  border-radius: 8px;
  transition: background-color 0.15s;
}

.share-menu-toggle-item:hover {
  background-color: #f5f5f5;
}

.share-menu-toggle-item input[type="checkbox"] {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  margin-top: 2px;
  accent-color: #2196f3;
  cursor: pointer;
}

.share-menu-toggle-item input[type="checkbox"]:disabled {
  cursor: wait;
  opacity: 0.5;
}

.share-menu-toggle-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.share-menu-toggle-label {
  font-size: 14px;
  font-weight: 500;
  color: #333;
}

.share-menu-toggle-description {
  font-size: 12px;
  line-height: 1.4;
  color: #666;
}

/* Itinerary item info line with source tags */
.itinerary-item-info {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}

.source-tag {
  display: inline-flex;
  gap: 3px;
  align-items: center;
  padding: 2px 6px;
  font-size: 10px;
  font-weight: 600;
  text-shadow: none;
  border-radius: 10px;
}

.source-tag .material-symbols-outlined {
  font-size: 12px;
}

.source-tag.shared {
  color: white;
  background-color: rgb(33 150 243 / 90%);
}

.source-tag.booking {
  color: white;
  background-color: rgb(76 175 80 / 90%);
}

.source-tag.local {
  color: white;
  background-color: rgb(158 158 158 / 90%);
}

/* Delete button for local itineraries */
.itinerary-delete-local {
  position: absolute;
  top: 10px;
  right: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  color: white;
  cursor: pointer;
  background: rgb(244 67 54 / 80%);
  border: none;
  border-radius: 50%;
  opacity: 0;
  transition: opacity 0.2s, background-color 0.2s;
}

.itinerary-item:hover .itinerary-delete-local {
  opacity: 1;
}

.itinerary-delete-local:hover {
  background: rgb(244 67 54);
}

.itinerary-delete-local .material-symbols-outlined {
  font-size: 18px;
}

/* Mobile screens: panel is full-width, use larger header fonts */
@media (width <= 768px) {
  .itinerary-panel-header {
    padding: 12px 16px;
  }

  .itinerary-panel-header > .itinerary-title {
    font-size: 16px;
  }

  .toggle-btn {
    padding: 6px 12px;
    font-size: 10px;
  }

  .details-header .itinerary-title {
    font-size: 24px;
  }
}

.sailing-leg-indicator {
  display: flex;
  gap: 4px;
  align-items: center;
  padding: 0;
  margin-bottom: -6px;
  font-size: 11px;
  color: #888;
}

.sailing-leg-indicator .material-symbols-outlined {
  font-size: 14px;
}

/* Narrow portrait screens: shrink header elements further so close button stays visible */
@media (width <= 400px) and (orientation: portrait) {
  .itinerary-panel-header {
    padding: 3px 16px;
  }

  .itinerary-panel-header > .itinerary-title {
    font-size: 20px;
  }

  .toggle-btn {
    padding: 6px;
    font-size: 15px;
  }

  .details-header {
    gap: 6px;
  }

  .details-header .itinerary-title {
    font-size: 15px;
  }
}

.new-day-divider {
  display: flex;
  align-items: center;
  padding: 4px 16px;
}

.new-day-divider::before,
.new-day-divider::after {
  flex: 1;
  height: 1px;
  content: '';
  background-color: #ccc;
}

.new-day-button {
  display: flex;
  gap: 3px;
  align-items: center;
  padding: 2px 12px;
  margin: 0 8px;
  font-size: 12px;
  font-weight: 500;
  color: #666;
  white-space: nowrap;
  cursor: pointer;
  background: white;
  border: 1px solid #ccc;
  border-radius: 999px;
  transition: background-color 0.2s, color 0.2s, border-color 0.2s;
}

.new-day-button:hover {
  color: #333;
  background-color: #f5f5f5;
  border-color: #999;
}

.new-day-button .material-symbols-outlined {
  font-size: 14px;
}

  /* U15 of the 2026-08-06 batch-2 plan (R16) — the crew summary row.
     `space-between` with the counts absent leaves the button flush left, which
     is where it belongs when it is the row's only occupant; there is no
     placeholder holding its position. */
  .crew-summary-row.svelte-8ugp5f {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 12px;
    padding: 8px 12px;
    border: 1px solid #e2e8f0;
    border-radius: 8px;
    background-color: #f8fafc;
  }
  .crew-summary-counts.svelte-8ugp5f {
    font-size: 13px;
    color: #334155;
    min-width: 0;
  }
  .crew-invite-button.svelte-8ugp5f {
    display: inline-flex;
    flex-shrink: 0;
    gap: 6px;
    align-items: center;
    /* Pinned to the row's right edge even when it is the row's ONLY child.
       `space-between` on the parent puts a lone item at the START, so an
       anonymous visitor — who gets the CTA without the counts — saw the button
       jump to the left. `auto` keeps it right in both arrangements. */
    margin-left: auto;
    /* 44 px is the tap target the rest of the panel's controls hold to; the
       padding rather than a fixed height so the label can wrap on narrow
       panels without the text overflowing the box. */
    min-height: 44px;
    padding: 6px 12px;
    font-size: 13px;
    font-weight: 500;
    color: #0369a1;
    cursor: pointer;
    background: transparent;
    border: 1px solid #bae6fd;
    border-radius: 6px;
    transition: background-color 0.15s;
  }
  .crew-invite-button.svelte-8ugp5f:hover {
    background-color: #e0f2fe;
  }
  .crew-invite-button.svelte-8ugp5f .material-symbols-outlined:where(.svelte-8ugp5f) {
    font-size: 18px;
  }
  .crew-summary-error.svelte-8ugp5f {
    margin-bottom: 12px;
    font-size: 12px;
    color: #b91c1c;
  }

  /* U16 of the 2026-08-06 batch-2 plan (R17) — the two tab names inside the
     empty state's sentence.

     A <button> rather than a styled <span>, because it does something; the
     styling is what makes a button sit inside running text without breaking
     it. `display: inline` (not inline-block) so the sentence can wrap BETWEEN
     the words of "My itineraries" the way the surrounding prose does, and the
     font is inherited so the name reads as part of the sentence rather than as
     a control dropped into it. The underline is the only affordance, which is
     the convention for an inline action in a paragraph.

     No min-height: a 44 px tap target would tear the line apart. The
     underlined text is the target, and the whole sentence sits inside a panel
     whose other controls carry the larger target. */
  .crew-empty-tab-link.svelte-8ugp5f {
    display: inline;
    padding: 0;
    font: inherit;
    color: #0369a1;
    text-decoration: underline;
    cursor: pointer;
    background: none;
    border: none;
  }
  .crew-empty-tab-link.svelte-8ugp5f:hover {
    color: #075985;
  }
  .crew-empty-tab-link.svelte-8ugp5f:focus-visible {
    outline: 2px solid #0369a1;
    outline-offset: 2px;
  }

  /* U11 — Suggestion preview overlay. Positioned absolutely over the
     details-view body so the in-edit DOM stays alive in the background.
     Distinct background tint and an "Add to itinerary" CTA (styled to
     mirror InfoPanel.svelte's `add-to-itinerary-button`). */
  .itinerary-preview-overlay.svelte-8ugp5f {
    position: absolute;
    inset: 0;
    /* Must sit ABOVE `.itinerary-details-view` (z-index: 10) — that's the
       in-edit details body the overlay is meant to cover while previewing
       a curated suggestion. The previous value (5) left the editor on top
       so the overlay rendered into the DOM but was visually obscured. */
    z-index: 20;
    display: flex;
    flex-direction: column;
    /* `min-height: 0` lets the flex container shrink to its parent's height
       instead of growing to fit its (tall) child day list. Without this the
       overlay swells past the viewport and the document scrolls — producing
       a second page-level scrollbar on multi-day previews. */
    min-height: 0;
    background: linear-gradient(180deg, #eef6fb 0%, #ffffff 80%);
    overflow: hidden;
  }
  .itinerary-preview-header.svelte-8ugp5f {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 16px 12px;
    background: #dbeafe;
    border-bottom: 1px solid #bfdbfe;
  }
  .itinerary-preview-header-text.svelte-8ugp5f {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
  }
  .itinerary-preview-eyebrow.svelte-8ugp5f {
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #1d4ed8;
  }
  .itinerary-preview-title.svelte-8ugp5f {
    font-size: 18px;
    font-weight: 700;
    color: #111827;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .itinerary-preview-meta.svelte-8ugp5f {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    font-size: 13px;
    color: #374151;
  }
  .itinerary-preview-close.svelte-8ugp5f {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    cursor: pointer;
    color: #1f2937;
    border-radius: 50%;
  }
  .itinerary-preview-close.svelte-8ugp5f:hover {
    background: rgba(0, 0, 0, 0.06);
  }
  .itinerary-preview-body.svelte-8ugp5f {
    flex: 1 1 auto;
    /* `min-height: 0` is the load-bearing fix for the double-scrollbar:
       without it a flex item grows to fit its intrinsic content (the
       day list is ~2580px on a 6-day suggestion), pushing the document
       height past the viewport. `overflow-y: auto` only takes effect
       when the box can shrink, which requires the min-height clamp. */
    min-height: 0;
    min-width: 0;
    overflow-y: auto;
    padding: 12px 16px;
  }
  /* The shared `renderItineraryDetailsBody` snippet wraps content in
     `.itinerary-panel-body` + `.itinerary-steps`, which carry editor-context
     styles (`height: 100%; overflow-y: auto; padding-bottom: 80px`) that
     fight the preview overlay's own scroll container. Inside the preview
     overlay the outer `.itinerary-preview-body` owns the scroll; the inner
     wrapper just lays out naturally. */
  .itinerary-preview-body.svelte-8ugp5f .itinerary-panel-body:where(.svelte-8ugp5f) {
    height: auto;
    flex-grow: 0;
    overflow: visible;
    padding: 0;
  }
  .itinerary-preview-cover.svelte-8ugp5f {
    width: 100%;
    border-radius: 8px;
    margin-bottom: 12px;
    object-fit: cover;
    max-height: 180px;
  }
  /* CTA row positioned directly below the blue header. flex-shrink: 0 keeps
     it pinned above the scrollable body; horizontal padding + bottom margin
     visually pair it with the header band. */
  .itinerary-preview-add-row.svelte-8ugp5f {
    flex-shrink: 0;
    display: flex;
    justify-content: center;
    padding: 12px 16px 0;
    margin-bottom: 8px;
  }
  .itinerary-preview-add-row.svelte-8ugp5f .add-to-itinerary-button:where(.svelte-8ugp5f) {
    display: flex;
    gap: 6px;
    align-items: center;
    justify-content: center;
    width: 100%;
    padding: 10px 16px;
    font-family: "Open Sans", sans-serif;
    font-size: 14px;
    font-weight: 500;
    color: white;
    cursor: pointer;
    background: #4caf50;
    border: none;
    border-radius: 8px;
    transition:
      background-color 0.2s ease,
      opacity 0.2s ease;
  }
  .itinerary-preview-add-row.svelte-8ugp5f .add-to-itinerary-button:where(.svelte-8ugp5f):hover {
    background: #388e3c;
  }
  .itinerary-preview-add-row.svelte-8ugp5f .add-to-itinerary-button[disabled]:where(.svelte-8ugp5f) {
    opacity: 0.6;
    cursor: not-allowed;
  }
  .itinerary-preview-add-row.svelte-8ugp5f .add-to-itinerary-button:where(.svelte-8ugp5f) .material-symbols-outlined:where(.svelte-8ugp5f) {
    font-size: 20px;
  }
  /* When the preview is active, prevent pointer interaction with the
     underlying details-view (overlay is opaque already, but this keeps
     focus/keyboard semantics clean). */
  .itinerary-details-view.preview-active.svelte-8ugp5f {
    pointer-events: none;
  }
  .itinerary-preview-overlay.svelte-8ugp5f,
  .itinerary-preview-overlay.svelte-8ugp5f :where(.svelte-8ugp5f) {
    pointer-events: auto;
  }
  html.dark .itinerary-preview-overlay {
    background: linear-gradient(180deg, #1e3a5f 0%, #1f2937 80%);
  }
  html.dark .itinerary-preview-header {
    background: #1e3a8a;
    border-bottom-color: #1d4ed8;
  }
  html.dark .itinerary-preview-eyebrow {
    color: #93c5fd;
  }
  html.dark .itinerary-preview-title,
  html.dark .itinerary-preview-meta {
    color: #f3f4f6;
  }
  /* My-tab tile like button — scaled to 70% so it sits unobtrusively on the
     small tile thumbnail. The wrapper still occupies its layout slot; only
     the button visual shrinks. transform-origin centers the scale on the
     wrapper's centroid. */
  .itinerary-item-like.svelte-8ugp5f .like-itinerary-button {
    transform: scale(0.7);
    transform-origin: center;
  }

  /* Dark mode (class-based — html.dark) lives here so :global() compiles. */
  html.dark .itinerary-panel-inner,
  html.dark .itinerary-panel-header,
  html.dark .itinerary-panel-body,
  html.dark .itinerary-list-view,
  html.dark .itinerary-details-view,
  html.dark .itinerary-title,
  html.dark .itinerary-item-title,
  html.dark .step-poi-name,
  html.dark .step-text,
  html.dark .details-header h2,
  html.dark .details-header h3,
  html.dark .step,
  html.dark .step-content {
    color: #f3f4f6;
  }
  /* The inner / list / body / details containers ship with hard-coded white
     backgrounds in the CSS file — override them here so the gaps between
     itinerary cards read as the dark surface, not flashes of white. */
  html.dark .itinerary-panel-inner,
  html.dark .itinerary-panel-body,
  html.dark .itinerary-list-view,
  html.dark .itinerary-details-view {
    background-color: #1f2937;
  }
  html.dark .itinerary-total-distance,
  html.dark .step-detail-indicator {
    color: #d1d5db;
  }
  html.dark .itinerary-close-button,
  html.dark .itinerary-icon-button,
  html.dark .itinerary-button {
    color: #f3f4f6;
    background-color: #374151;
    border-color: #4b5563;
  }
  html.dark .itinerary-close-button:hover,
  html.dark .itinerary-icon-button:hover,
  html.dark .itinerary-button:hover {
    background-color: #4b5563;
  }
  html.dark .itinerary-separator {
    background-color: rgb(255 255 255 / 10%);
  }
  html.dark .itinerary-item {
    color: #f3f4f6;
    background: #1f2937;
    border-color: #4b5563;
  }
  html.dark .itinerary-item:hover {
    background: #273342;
    border-color: #6b7280;
  }
  html.dark .itinerary-item.selected {
    border-color: #3b82f6;
  }
  /* U10 — the like-button pill on My-tab tiles ships with a white/75%
     background in ItineraryPanel.css; keep it a dark translucent surface in
     dark theme so the gray-300 unliked heart (and the red-400 liked heart)
     read clearly against it. */
  html.dark .itinerary-item-like {
    background: rgb(31 41 55 / 75%);
  }
  html.dark .itinerary-pill {
    color: #d1d5db;
    background: #374151;
  }
  html.dark .itinerary-view-on-map,
  html.dark .itinerary-add-btn {
    color: #f3f4f6;
    background: #374151;
    border-color: #4b5563;
  }
  html.dark .itinerary-view-on-map:hover,
  html.dark .itinerary-add-btn:hover {
    background: #4b5563;
  }
  html.dark .step-line {
    background: rgb(255 255 255 / 18%);
  }
  html.dark .itinerary-title-input {
    color: #f3f4f6;
    background: #1f2937;
    border-color: #4b5563;
  }
  html.dark .itinerary-title-input:focus {
    border-color: #3b82f6;
  }
  html.dark .new-day-button {
    color: #d1d5db;
    background: #374151;
    border-color: #4b5563;
  }
  html.dark .new-day-button:hover {
    color: #f3f4f6;
    background-color: #4b5563;
    border-color: #6b7280;
  }
  html.dark .proposal-alert,
  html.dark .reorder-proposal {
    color: #f3f4f6;
    background: #1f2937;
    border-color: #4b5563;
  }
  html.dark .ignore-button {
    color: #d1d5db;
    background: transparent;
    border-color: #4b5563;
  }
  html.dark .ignore-button:hover {
    background: #374151;
  }

  /* Suggested/My segmented toggle */
  html.dark .itinerary-mode-toggle {
    background-color: #374151;
  }
  html.dark .toggle-btn {
    color: #d1d5db;
  }
  /* Same hairline as light mode, lifted off the dark strip background. */
  html.dark .toggle-btn + .toggle-btn::before {
    background-color: #4a5568;
  }

  html.dark .toggle-btn:hover {
    color: #f3f4f6;
  }
  /* .toggle-btn.active keeps its blue accent — already legible. */

  /* "Starting from / Ending at" banners and inline change/select-point
     buttons live behind the depth-layer-fm-sky-* utilities (defined in
     packages/ui/src/app.css) which only generate a single light-mode
     background-color. Override the surfaces under html.dark so the banner
     and the in-banner pill button no longer flash bright sky-blue. */
  html.dark .depth-layer-no-hover-fm-sky-200 {
    background-color: oklch(36.59% 0.091 244.66) !important;
    color: #f3f4f6;
  }
  html.dark .depth-layer-fm-sky-100 {
    background-color: oklch(47.81% 0.124 246.36) !important;
    color: #f3f4f6;
  }

  /* Editing-view chrome */
  html.dark .details-header {
    background-color: #1f2937;
  }
  html.dark .search-start-point-message {
    color: #d1d5db;
    background-color: #374151;
    border-color: #6b7280;
  }
  html.dark .search-start-point-message .material-symbols-outlined {
    color: #60a5fa;
  }

  /* U3 — "Start where I am", the choose-start notice's second option.
     Scoped here rather than in ItineraryPanel.css because these rules exist
     only to fit the new control into a notice whose layout the stylesheet
     already owns: the notice is a centred flex ROW of [pin icon, sentence],
     and the option has to sit under the sentence rather than beside the pin. */
  .start-point-options.svelte-8ugp5f {
    display: flex;
    flex-direction: column;
    /* NO row gap: the notice's own 24px line-height is the rhythm, and the
       three lines have to share it. An 8px gap here put the option 29.5px
       below the sentence's last line where the sentence's own lines are 24px
       apart, which reads as a spacing mistake rather than as a group. */
    /* Flush with the sentence's own left edge, not centred under it. Centred,
       the option floated free of the text it is an alternative to and read as
       a separate control; the notice as a whole is still centred by its
       stylesheet rule. */
    align-items: flex-start;
  }

  /* "or" + the button on one baseline. The "or" is plain text so it is not
     part of the link's hit area or its accessible name. `min-height` is the
     notice's line-height, so this row occupies exactly one text line even
     though the glyph inside it is taller than the label's ink. */
  .start-point-alternative.svelte-8ugp5f {
    display: inline-flex;
    gap: 6px;
    align-items: center;
    min-height: 24px;
  }

  /* Same link treatment as the sibling "start at {marina}", plus an icon: the
     two are alternatives and should read as one pair of choices. The icon is
     `my_location` — the map control's own glyph — so the two affordances that
     now run the SAME flow look like the same thing. */
  .start-at-my-location-link.svelte-8ugp5f {
    display: inline-flex;
    gap: 6px;
    align-items: center;
    padding: 0;
    /* `inherit`, exactly like the sibling `.start-at-plan-marina-link`. At its
       own 15px/22.5px it was a third type size in a three-line notice and broke
       the 24px rhythm on its own, gap or no gap. */
    font-size: inherit;
    line-height: inherit;
    color: #0369a1;
    cursor: pointer;
    background: none;
    border: none;
  }
  .start-at-my-location-link.svelte-8ugp5f:hover:not(:disabled) {
    color: #075985;
  }
  /* The underline belongs to the WORDS, not to the button. On the button it
     spanned the glyph too — and the glyph sits on its own baseline, a font
     size apart from the label, so the rule broke into two offset segments. */
  .start-at-my-location-link.svelte-8ugp5f:hover:not(:disabled) .start-at-my-location-label:where(.svelte-8ugp5f) {
    text-decoration: underline;
  }
  .start-at-my-location-link.svelte-8ugp5f:disabled {
    cursor: progress;
    opacity: 70%;
  }
  /* The notice sets every `.material-symbols-outlined` inside it to 28px and
     the accent blue — right for the pin, far too loud for a button glyph. */
  .start-at-my-location-link.svelte-8ugp5f .material-symbols-outlined:where(.svelte-8ugp5f) {
    font-size: 18px;
    color: inherit;
  }
  html.dark .start-at-my-location-link {
    color: #93c5fd;
  }
  html.dark .start-at-my-location-link:hover:not(:disabled) {
    color: #bfdbfe;
  }
  html.dark .itinerary-days-controls {
    background: #1f2937;
  }
  html.dark .days-toggle-button {
    color: #d1d5db;
    background: #374151;
    border-color: #4b5563;
  }
  html.dark .days-toggle-button:hover {
    color: #f3f4f6;
    background: #4b5563;
    border-color: #6b7280;
  }

  /* In-panel "Share with crew" / "Shared with crew" button.
     Two states, both in the blue palette but visually distinct so the
     user can read the attached state at a glance without parsing the
     label:
       - not attached (primary action): solid blue background + white text.
       - attached (state, "done"): blue-tinted outline button — blue border,
         pale blue background, dark blue text. Reads as a checked-off state
         rather than a CTA, without leaving the brand palette.
     Disabled state (HTML disabled + opacity-60 + cursor-not-allowed)
     applies to both the canEdit=false viewer and the in-flight state. */
  .add-to-plan-button.svelte-8ugp5f {
    color: #ffffff;
    background: #2563eb;
    border-color: #1d4ed8;
  }
  .add-to-plan-button.svelte-8ugp5f:hover:not([disabled]) {
    color: #ffffff;
    background: #1d4ed8;
    border-color: #1e40af;
  }
  .add-to-plan-button.svelte-8ugp5f .material-symbols-outlined:where(.svelte-8ugp5f) {
    color: #ffffff;
  }
  .add-to-plan-button.added.svelte-8ugp5f {
    color: #1e40af;
    background: #eff6ff;
    border-color: #2563eb;
  }
  .add-to-plan-button.added.svelte-8ugp5f:hover:not([disabled]) {
    color: #1e3a8a;
    background: #dbeafe;
    border-color: #1d4ed8;
  }
  .add-to-plan-button.added.svelte-8ugp5f .material-symbols-outlined:where(.svelte-8ugp5f) {
    color: #1d4ed8;
  }
  .add-to-plan-button[disabled].svelte-8ugp5f {
    opacity: 0.6;
    cursor: not-allowed;
  }
  html.dark .add-to-plan-button {
    color: #ffffff;
    background: #1d4ed8;
    border-color: #1e3a8a;
  }
  html.dark .add-to-plan-button:hover:not([disabled]) {
    background: #1e40af;
    border-color: #1e3a8a;
  }
  html.dark .add-to-plan-button .material-symbols-outlined {
    color: #ffffff;
  }
  html.dark .add-to-plan-button.added {
    color: #bfdbfe;
    background: #1e3a8a;
    border-color: #3b82f6;
  }
  html.dark .add-to-plan-button.added:hover:not([disabled]) {
    color: #dbeafe;
    background: #1e40af;
    border-color: #60a5fa;
  }
  html.dark .add-to-plan-button.added .material-symbols-outlined {
    color: #93c5fd;
  }
  html.dark .step-description {
    color: #d1d5db;
  }

  /* Day-row labels in the editing view: ".day-label" carries the auto
     "Relaxing at sea" / custom day title and was #333 — disappears on
     the dark blue day card. The contenteditable variants need the same
     treatment, plus a sane focus surface. */
  html.dark .day-label {
    color: #f3f4f6;
  }
  html.dark .day-label-input:hover {
    border-color: #4b5563;
  }
  html.dark .day-label-input:focus {
    color: #f3f4f6;
    background: #1f2937;
    border-color: #6b7280;
  }
  html.dark .day-label-input:empty::before {
    color: #6b7280;
  }

  /* Inline date editor inside the day-title header. Dashed underline cues
     editability without competing with the surrounding day-number colour. */
  .day-date-btn.svelte-8ugp5f {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    color: inherit;
    cursor: pointer;
    text-decoration: underline dotted;
    text-underline-offset: 2px;
  }
  .day-date-btn.svelte-8ugp5f:hover {
    text-decoration: underline;
  }
  .day-date-input.svelte-8ugp5f {
    font: inherit;
    border: 1px solid var(--color-slate-300, #cbd5e1);
    border-radius: 0.25rem;
    padding: 0 0.25rem;
    color: inherit;
    background: transparent;
  }
  /* Anchor for the custom calendar dropdown; the native picker popup is
     replaced by <DayDateCalendar>, so hide the browser's own trigger icon. */
  .day-date-edit-wrap.svelte-8ugp5f {
    position: relative;
    display: inline-block;
  }
  .day-date-input.svelte-8ugp5f::-webkit-calendar-picker-indicator {
    display: none;
  }

  /* Share menu dropdown: hardcoded white background is invisible / unreadable
     in dark mode. Override with a dark surface that matches the panel palette. */
  html.dark .share-menu-dropdown {
    background-color: #374151;
    color: #f3f4f6;
  }
  html.dark .share-menu-item {
    color: #f3f4f6;
  }
  html.dark .share-menu-item:hover {
    background-color: #4b5563;
  }

  /* ── U18 (R18, R21) — the per-tile control cluster ──────────────────────── */

  /* Tiles clipped their cover photo with `overflow: hidden`, which also clips
     anything anchored INSIDE them — a share dropdown on a 150 px tile would
     have been invisible rather than merely cramped. The clip moves onto the
     image itself (13 px = the 15 px outer radius minus the 2 px border), and
     the decoration pseudo-element gets the inset the clip used to give it, so
     the tile renders as before while the menu can escape. */
  .itinerary-item.svelte-8ugp5f {
    overflow: visible;
  }

  /* Letting the menu ESCAPE the tile (above) is not the same as letting it sit
     ABOVE the next one. Tiles are siblings painted in DOM order, so a dropdown
     hanging off tile N was overlapped by tile N+1 — and the tile below is
     exactly where a 150px tile's menu opens. Raising the whole tile, not just
     the menu, keeps the cluster and its dropdown in one stacking context.
     `:has()` scopes the lift to the tile that actually has a menu open, so the
     rest of the grid keeps its natural order. */
  /* `:global()` on the dropdown half is required, not stylistic: the element is
     rendered by ShareItineraryMenu and carries ITS scope hash, so the scoped
     selector matched nothing and Svelte pruned the whole rule as unused. */
  .itinerary-item.svelte-8ugp5f:has(.share-menu-dropdown) {
    z-index: 20;
    /* The share menu's click-away backdrop is position:fixed INSIDE this
       tile, and the depth-layer hover scale makes the tile its containing
       block: hovering shrinks the backdrop off the pointer, which ends the
       hover, which regrows it — an arrow/hand cursor flicker. Freeze the
       tile while its menu is open. */
    scale: none;
    transition: none;
  }

  .itinerary-item.svelte-8ugp5f img:where(.svelte-8ugp5f) {
    border-radius: 13px;
  }

  .itinerary-item.svelte-8ugp5f::before {
    inset: 0;
    border-radius: 13px;
  }

  /* Two controls at the tile's trailing edge, like then share. 44 px targets
     with an 8 px gap: mis-hitting like and getting share opens a full-viewport
     backdrop menu, which is a far more disruptive slip than the reverse.
     z-index clears the title block, which is also absolutely positioned. */
  .itinerary-tile-controls.svelte-8ugp5f {
    position: absolute;
    top: 6px;
    right: 6px;
    z-index: 3;
    display: flex;
    /* A COLUMN down the tile's right edge, like on top. Side by side, the pair
       ate horizontal room the title needs — "Port of Lavrio → Plaia Epidavrou"
       ran under them — and stacking gives each control the tile's full right
       margin instead of half of it. Like stays first in the DOM, so column
       order and reading order agree without an `order` override. */
    flex-direction: column;
    gap: 8px;
    align-items: center;
  }

  /* The like chip keeps its global look (translucent disc, 22 px heart) and
     loses only the absolute positioning it needed while it was the tile's one
     control. Sized to the same 44 px floor as its neighbour. */
  .itinerary-tile-controls.svelte-8ugp5f .itinerary-item-like:where(.svelte-8ugp5f) {
    position: static;
    width: 44px;
    height: 44px;
  }

  .itinerary-tile-share.svelte-8ugp5f {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    color: #1f2937;
    cursor: pointer;
    background: rgb(255 255 255 / 75%);
    backdrop-filter: blur(2px);
    border: none;
    border-radius: 999px;
    box-shadow: 0 1px 3px rgb(0 0 0 / 15%);
  }

  .itinerary-tile-share.svelte-8ugp5f .material-symbols-outlined:where(.svelte-8ugp5f) {
    font-size: 22px;
  }


  .unit-selector.svelte-1bu9hkj {
    display: flex;
    color: white;
    margin-left: 5px;
    font-family: 'Open Sans', sans-serif;
    font-size: 14px;
    gap: 3px;
  }
  .unit-selector.svelte-1bu9hkj span:where(.svelte-1bu9hkj) {
    padding: 2px 5px;
    cursor: pointer;
    border-radius: 3px;
    opacity: 0.8;
    background: #a9a9a9;
    color: black;
  }
  .unit-selector.svelte-1bu9hkj span.selected:where(.svelte-1bu9hkj) {
    background-color: #007cbf;
    color: white;
  }
  .distance-display-container.svelte-1bu9hkj {
    position: absolute;
    transform: translateX(-50%);
    z-index: 1001;
    pointer-events: auto;
    transition: top 0.2s ease;
  }

  .distance-input-wrapper.svelte-1bu9hkj {
    display: flex;
    align-items: center;
    background-color: rgba(0, 0, 0, 0.7);
    border-radius: 5px;
    padding: 5px 10px;
  }

  .distance-display.svelte-1bu9hkj {
    background-color: transparent;
    color: white;
    font-family: 'Open Sans', sans-serif;
    font-size: 14px;
    border: none;
    text-align: right;
  }

  /* Hide arrows from number input */
  .distance-display.svelte-1bu9hkj::-webkit-inner-spin-button,
  .distance-display.svelte-1bu9hkj::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
  }
  .distance-display.svelte-1bu9hkj {
    -moz-appearance: textfield;
  }


  @keyframes svelte-7ooc5l-spin {
    from {
      transform: rotate(0deg);
    }
    to {
      transform: rotate(360deg);
    }
  }

  .spin.svelte-7ooc5l {
    animation: svelte-7ooc5l-spin 1s linear infinite;
  }

  .map-control-button.svelte-7ooc5l {
    position: relative;
    padding: 10px;
    background-color: #fff;
    color: rgba(0, 0, 0, 0.7);
    border: 0;
    border-radius: 50%;
    cursor: pointer;
    width: 40px;
    height: 40px;
    display: flex;
    justify-content: center;
    align-items: center;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
    transition: background-color 0.3s ease;
  }

  .map-control-button.is-on.svelte-7ooc5l {
    background-color: #e0e0e0;
  }

    .map-control-button.svelte-7ooc5l:hover {
        background-color: #f5f5f5;
    }

    .map-control-button.is-on.svelte-7ooc5l:hover {
        background-color: #d0d0d0;
    }

  /* U8 — "my menu is open", keyed off `aria-expanded="true"` and NOT off
     `.is-on`: on the layers button `.is-on` still means "satellite showing",
     so the two must be able to hold independently — grey fill without the
     ring (satellite, menu closed), ring on white (roadmap, menu open), both.
     A ring rather than a fill so it composes with `.is-on`'s fill instead of
     replacing it. 2.5px of the brand green, the same ring
     `MfmControlButton.is-on` wears, because MfmMenu's `beside-*` caret is
     drawn in that colour and sized to start where a 2.5px ring ends. Declared
     before the accent block so an accent button's own ring (same specificity,
     later in source) is untouched. */
  .map-control-button.is-open.svelte-7ooc5l {
    box-shadow:
      0 0 0 2.5px #2bbe4a,
      0 2px 6px rgba(0, 0, 0, 0.16);
  }

  .badge.svelte-7ooc5l {
    position: absolute;
    left: 28px;
        bottom: 28px;
    width: 12px;
    height: 12px;
    background-color: #d32f2f;
    border-radius: 50%;
  }

  /* "Ring + glow" accent — itinerary entry-point button.
     Default fills the pill with the same brand green as the ring (the
     glyph is white). When pressed (`:active`) or while the panel is
     open (`.is-on`), the pill flips to a white background with the
     green ring preserved and the glyph in brand green. */
  .map-control-button.accent-ring-glow.svelte-7ooc5l {
    background-color: #2bbe4a;
    color: #fff;
    box-shadow:
      0 0 0 2.5px #2bbe4a,
      0 0 0 6px rgba(43, 190, 74, 0.18),
      0 2px 6px rgba(0, 0, 0, 0.12);
    transition: background-color 0.3s ease, color 0.3s ease, box-shadow 0.2s ease, transform 0.1s ease;
  }
  .map-control-button.accent-ring-glow.svelte-7ooc5l:hover {
    background-color: #2bbe4a;
    color: #fff;
    box-shadow:
      0 0 0 2.5px #2bbe4a,
      0 0 0 6px rgba(43, 190, 74, 0.30),
      0 2px 6px rgba(0, 0, 0, 0.12);
  }
  .map-control-button.accent-ring-glow.svelte-7ooc5l:active,
  .map-control-button.accent-ring-glow.is-on.svelte-7ooc5l,
  .map-control-button.accent-ring-glow.is-on.svelte-7ooc5l:hover {
    background-color: #fff;
    color: #18a33a;
    box-shadow:
      0 0 0 2.5px #2bbe4a,
      0 0 0 6px rgba(43, 190, 74, 0.18),
      0 2px 6px rgba(0, 0, 0, 0.12);
  }
  .map-control-button.accent-ring-glow.svelte-7ooc5l:active {
    transform: scale(0.96);
  }

  html.dark {
    .map-control-button.svelte-7ooc5l {
      background-color: #1f2937;
      color: #f3f4f6;
      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.6);
    }
    .map-control-button.is-on.svelte-7ooc5l {
      background-color: #4b5563;
    }
    .map-control-button.svelte-7ooc5l:hover {
      background-color: #374151;
    }
    .map-control-button.is-on.svelte-7ooc5l:hover {
      background-color: #6b7280;
    }
    /* Same lighter green MfmControlButton's dark `.is-on` ring and MfmMenu's
       dark caret use, so the ring and its caret still read as one shape. */
    .map-control-button.is-open.svelte-7ooc5l {
      box-shadow:
        0 0 0 2.5px #35d357,
        0 2px 6px rgba(0, 0, 0, 0.5);
    }
    /* Dark basemaps need a slightly stronger glow alpha for legibility,
       per the spec's "Edge Cases" note. Default keeps the green fill so
       the button reads as a primary action; pressed/open flips to white
       with the green ring still doing the work. */
    .map-control-button.accent-ring-glow.svelte-7ooc5l {
      background-color: #2bbe4a;
      color: #fff;
      box-shadow:
        0 0 0 2.5px #2bbe4a,
        0 0 0 6px rgba(43, 190, 74, 0.28),
        0 2px 6px rgba(0, 0, 0, 0.4);
    }
    .map-control-button.accent-ring-glow.svelte-7ooc5l:hover {
      background-color: #2bbe4a;
      color: #fff;
      box-shadow:
        0 0 0 2.5px #2bbe4a,
        0 0 0 6px rgba(43, 190, 74, 0.38),
        0 2px 6px rgba(0, 0, 0, 0.4);
    }
    .map-control-button.accent-ring-glow.svelte-7ooc5l:active,
    .map-control-button.accent-ring-glow.is-on.svelte-7ooc5l,
    .map-control-button.accent-ring-glow.is-on.svelte-7ooc5l:hover {
      background-color: #fff;
      color: #18a33a;
      box-shadow:
        0 0 0 2.5px #2bbe4a,
        0 0 0 6px rgba(43, 190, 74, 0.28),
        0 2px 6px rgba(0, 0, 0, 0.4);
    }
  }


  .map-controls-container.svelte-1p5tydi {
    position: absolute;
    right: 10px;
    /* The collide-anyway default for the compact rule below, which is the only
       one low enough to meet the weather datetime bar — the 180px resting
       position already clears it. `weatherClearanceStyle` overrides this inline
       with 0px once the bar provably cannot reach this cluster. Declared here
       rather than on `.compact` so both live in one place. */
    --weather-clearance: var(--weather-overlay-h, 0px);
    /* 180px clears Google's own Street View and Camera controls, which are
       pinned to this same corner (MapComponent's `mapOptions`, RIGHT_BOTTOM).
       Measured: camera tops out 148px above the map's bottom edge, so this
       leaves 32px. Both this cluster and those two controls changed corners
       together precisely so this relationship — and this number — did not have
       to change. */
    bottom: 180px;
    /* Item 6 — was `1`, which trapped this whole stacking context BELOW
       `.weatherSliderOverlay` (z-index 5). FilterMenu's inner `z-[1000]` could
       never escape it, so the filter menu painted under the weather datetime
       bar. Lifting the container lifts the menu with it.

       6, not something larger: the AI bottom sheet lives at z-aibar (1300) and
       must stay above the map chrome. Anything >= 1300 here would put the map
       tools over the sheet. */
    z-index: 6;
    display: flex;
    flex-direction: column;
    gap: 33px;
    transition: transform 0.3s ease-in-out, bottom 0.3s ease-in-out, right 0.3s ease-in-out;
  }

  .edit-locations-wrapper.svelte-1p5tydi {
    position: relative;
  }

  /* `display: flex`, not the default block, so the button never sits on a
     line box whose strut could add a few px of slack under its 40px. The
     column's height arithmetic (`mapToolsButtonCount` / `TOOLS_BUTTON_HEIGHT`
     in mfmClusterLayout.ts) assumes exactly 40px per button, so the slack
     would move the shared reflow threshold. */
  .maptype-toggle-wrapper.svelte-1p5tydi {
    position: relative;
    display: flex;
  }

  /* A3/U8 — MapControlButton's own circle is 40px (below the WCAG 2.5.5 /
     Apple HIG 44px touch-target floor MfmControlButton already holds itself
     to elsewhere in this chrome). Rather than resizing the shared component
     — which would also grow "Measure distance" and "Edit Locations" and
     change the 33px-gap column arithmetic `mapToolsButtonCount`/
     `TOOLS_BUTTON_HEIGHT` in mfmClusterLayout.ts pin — this expands only the
     new button's HIT area via an absolutely-positioned pseudo-element, the
     same technique MapComponent.svelte's `.weatherOverlayClose::after` uses.
     40px + 2×2px inset = 44px, with no added box in the flex column. */
  .maptype-toggle-wrapper .map-control-button::after {
    content: '';
    position: absolute;
    inset: -2px;
  }

  /* Opens LEFTWARD, toward the viewport interior — this cluster is bottom-right.
     The offset is the button's 40px plus a 10px gap. */
  .edit-locations-menu.svelte-1p5tydi {
    position: absolute;
    right: 50px;
    top: 0;
    background: white;
    border-radius: 8px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
    min-width: 180px;
    overflow: hidden;
    z-index: 10;
  }

  .edit-locations-menu-item.svelte-1p5tydi {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 12px 16px;
    border: none;
    background: white;
    cursor: pointer;
    font-size: 14px;
    color: #333;
    text-align: left;
    transition: background-color 0.15s;
  }

  .edit-locations-menu-item.svelte-1p5tydi:hover:not(:disabled) {
    background: #f5f5f5;
  }

  .edit-locations-menu-item.svelte-1p5tydi:disabled {
    opacity: 0.6;
    cursor: not-allowed;
  }

  .edit-locations-menu-item.svelte-1p5tydi:not(:last-child) {
    border-bottom: 1px solid #eee;
  }

  .edit-locations-menu-item.svelte-1p5tydi .material-symbols-outlined:where(.svelte-1p5tydi) {
    font-size: 20px;
    color: #666;
  }

  /* Dynamic panel-aware positioning is handled via inline style.
     The transition ensures smooth movement when panel resizes. */

  /* U1 (plan 2026-05-27-001) — numbered search-results panel.
     Anchored to the same left-edge column as the floating map controls,
     but sits above them so the buttons remain reachable. The badge uses the
     same #1a73e8 accent the FilterMenu uses for the active search-results
     state (≥4.5:1 contrast with white text per WCAG 2.1 AA). */
  .search-results-panel.svelte-1p5tydi {
    position: absolute;
    left: 10px;
    /* A2/U1: was a flat 60px, tuned to sit below Google's Map/Satellite
       toggle — which U1 turns off (`mapTypeControl: false`), making that
       number arbitrary. The panel now clears the overlay chrome's band
       instead, reading the ONE declaration of its height from
       MapChrome.svelte so the two cannot drift; the literal fallback keeps
       the panel correct if the chrome is ever absent. */
    top: calc(var(--map-chrome-h, 60px) + 10px);
    z-index: 2;
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-width: 240px;
    max-height: calc(100vh - 200px);
    padding: 6px;
    background: rgba(255, 255, 255, 0.96);
    border-radius: 8px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
    overflow: hidden;
  }

  html.dark .search-results-panel.svelte-1p5tydi {
    background: rgba(31, 41, 55, 0.96);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.6);
  }

  .search-results-header.svelte-1p5tydi {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 2px 4px 6px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
    flex: 0 0 auto;
  }

  html.dark .search-results-header.svelte-1p5tydi {
    border-bottom-color: rgba(255, 255, 255, 0.08);
  }

  .search-results-title.svelte-1p5tydi {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 11px;
    font-weight: 500;
    color: #6b7280;
    line-height: 1.2;
    letter-spacing: 0.02em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  html.dark .search-results-title.svelte-1p5tydi {
    color: #9ca3af;
  }

  .search-results-list.svelte-1p5tydi {
    display: flex;
    flex-direction: column;
    gap: 6px;
    overflow-y: auto;
    overflow-x: hidden;
    padding-top: 4px;
    min-height: 0;
  }

  /* Close × — sits in the header so it stays put while the list scrolls. */
  .search-results-close.svelte-1p5tydi {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.04);
    color: #6b7280;
    cursor: pointer;
    flex: 0 0 auto;
    transition: background-color 0.15s, color 0.15s;
  }

  .search-results-close.svelte-1p5tydi .material-symbols-outlined:where(.svelte-1p5tydi) {
    font-size: 16px;
    line-height: 1;
  }

  .search-results-close.svelte-1p5tydi:hover {
    background: rgba(0, 0, 0, 0.10);
    color: #111827;
  }

  .search-results-close.svelte-1p5tydi:focus-visible {
    outline: 2px solid #1a73e8;
    outline-offset: 1px;
  }

  html.dark .search-results-close.svelte-1p5tydi {
    background: rgba(255, 255, 255, 0.08);
    color: #d1d5db;
  }

  html.dark .search-results-close.svelte-1p5tydi:hover {
    background: rgba(255, 255, 255, 0.16);
    color: #f9fafb;
  }

  .search-result-item.svelte-1p5tydi {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-height: 32px;
    padding: 4px 8px;
    border: none;
    background: transparent;
    cursor: pointer;
    text-align: left;
    border-radius: 6px;
    transition: background-color 0.15s;
  }

  .search-result-item.svelte-1p5tydi:hover {
    background: #f5f5f5;
  }

  html.dark .search-result-item.svelte-1p5tydi:hover {
    background: #374151;
  }

  .search-result-item.svelte-1p5tydi:focus-visible {
    outline: 2px solid #1a73e8;
    outline-offset: 1px;
  }

  .search-result-badge.svelte-1p5tydi {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 22px;
    padding: 0 4px;
    border-radius: 11px;
    background: #1a73e8;
    color: #ffffff;
    font-size: 12px;
    font-weight: 600;
    line-height: 1;
    /* Contrast: #ffffff on #1a73e8 ≈ 4.86:1, passes WCAG AA for small text. */
  }

  /* Featured (recommended) rows get a warmer accent to match the
     marker layer's gold "Crown of Waves" glow. */
  .search-result-item.featured.svelte-1p5tydi .search-result-badge:where(.svelte-1p5tydi) {
    background: #b8860b;
    /* #ffffff on #b8860b ≈ 4.51:1, passes WCAG AA. */
  }

  .search-result-label.svelte-1p5tydi {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 13px;
    line-height: 1.2;
    color: #333;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  html.dark .search-result-label.svelte-1p5tydi {
    color: #f3f4f6;
  }

  /* Compact (mobile / short viewports): keep the panel anchored at the
     top-left, below the overlay chrome, but cap height tighter so the
     content below stays visible. Same offset as the base rule — the chrome
     band does not change height with the cluster's compact mode. */
  .search-results-panel.compact.svelte-1p5tydi {
    left: 10px;
    top: calc(var(--map-chrome-h, 60px) + 10px);
    max-width: calc(100vw - 20px);
    max-height: 50vh;
  }

  /* Compact tightens the spacing and drops the cluster toward the corner. It
     keeps the base `flex-direction: column` — a portrait phone is narrow, not
     short, and the row it used to get here spent width it did not have.

     The clearance var rides on top so the column clears the weather datetime
     bar, which at this width really does span under it. 0 when the bar is
     absent or provably out of reach, so the resting position is the 35px base. */
  .map-controls-container.compact.svelte-1p5tydi {
    bottom: max(35px, calc(35px + var(--weather-clearance, 0px) + var(--ai-bar-bottom-h, 0px)));
    right: 10px;
    gap: 20px;
  }

  /* Short viewports that are NOT landscape phones still reflow to a row, which
     is the case the row was introduced for: buttons stacked do not fit above the
     fold. A landscape phone is a column again — the weather bar narrows at both
     ends so the two columns can stand in the space it vacates, which costs one
     band of a 390px-tall screen instead of three.

     Plain `row`, not row-reverse: the rule is "whichever child sits at the
     bottom of the column sits nearest the corner in the row", and that child is
     the last one. Right-anchored, last-last means NOT reversing. The mfm cluster
     takes the opposite value for exactly the same reason, and that argument has
     to survive the move off `.compact.short` intact — the rule still fires for
     every short viewport outside the phone-landscape audience. */
  .map-controls-container.is-row.svelte-1p5tydi {
    flex-direction: row;
  }

  /* In the ROW the menu cannot open sideways — there is no room beside the
     button — so it goes straight up instead. The column, phone landscape
     included, keeps the base rule's leftward opening into empty map.

     Aligned LEFT here, the mirror of the base rule's `right`. The row is
     right-anchored and this button is its first child, so it sits at the row's
     LEFT end: growing the menu rightward keeps it inside the row's own
     footprint, while `right: 0` would push it further left than the row itself
     reaches and off a narrow viewport. */
  .map-controls-container.is-row.svelte-1p5tydi .edit-locations-menu:where(.svelte-1p5tydi) {
    left: 0;
    right: auto;
    top: auto;
    bottom: 50px;
  }

  /* Class-based dark mode toggled by $lib/utils/theme.ts on <html class="dark">. */
  html.dark .edit-locations-menu.svelte-1p5tydi {
    background: #1f2937;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.6);
  }
  html.dark .edit-locations-menu-item.svelte-1p5tydi {
    background: #1f2937;
    color: #f3f4f6;
  }
  html.dark .edit-locations-menu-item.svelte-1p5tydi:hover:not(:disabled) {
    background: #374151;
  }
  html.dark .edit-locations-menu-item.svelte-1p5tydi:not(:last-child) {
    border-bottom-color: #374151;
  }
  html.dark .edit-locations-menu-item.svelte-1p5tydi .material-symbols-outlined:where(.svelte-1p5tydi) {
    color: #d1d5db;
  }


  @keyframes svelte-1j4lisl-spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
  }

  .spin.svelte-1j4lisl {
    animation: svelte-1j4lisl-spin 1s linear infinite;
  }

  .mfm-control-button.svelte-1j4lisl {
    position: relative;
    padding: 8px 12px;
    background-color: #2bbe4a;
    color: #fff;
    border: 0;
    /* A pill, not a circle — the silhouette IS the distinguishing signal. */
    border-radius: 12px;
    cursor: pointer;
    min-width: 48px;
    /* 44px is the WCAG 2.5.5 / Apple HIG minimum touch target, and this
       cluster is used one-handed on a moving boat — the case that most
       deserves the full target. Was 40px. */
    height: 44px;
    display: flex;
    justify-content: center;
    align-items: center;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
    transition: background-color 0.2s ease, box-shadow 0.2s ease, transform 0.1s ease;
  }

  .mfm-control-button.svelte-1j4lisl:hover {
    background-color: #23a83f;
  }

  /* Open/active: invert to a white pill with the green ring preserved, the same
     "pressed" language the itinerary button's accent already uses, so the two
     read as one family once U7 moves it in here. */
  .mfm-control-button.is-on.svelte-1j4lisl,
  .mfm-control-button.is-on.svelte-1j4lisl:hover {
    background-color: #fff;
    color: #18a33a;
    box-shadow:
      0 0 0 2.5px #2bbe4a,
      0 2px 6px rgba(0, 0, 0, 0.16);
  }

  .mfm-control-button.svelte-1j4lisl:active {
    transform: scale(0.96);
  }

  .mfm-control-button.svelte-1j4lisl:focus-visible {
    outline: 2px solid #18a33a;
    outline-offset: 2px;
  }

  .badge.svelte-1j4lisl {
    position: absolute;
    top: -3px;
    right: -3px;
    width: 12px;
    height: 12px;
    background-color: #d32f2f;
    border: 2px solid #fff;
    border-radius: 50%;
  }

  html.dark {
    .mfm-control-button.svelte-1j4lisl {
      background-color: #2bbe4a;
      color: #fff;
      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.6);
    }
    .mfm-control-button.svelte-1j4lisl:hover {
      background-color: #35d357;
    }
    /* Dark basemaps: keep the inverted state light enough to stay legible
       against a dark tile, and thicken the ring slightly for contrast. */
    .mfm-control-button.is-on.svelte-1j4lisl,
    .mfm-control-button.is-on.svelte-1j4lisl:hover {
      background-color: #f3f4f6;
      color: #157f2e;
      box-shadow:
        0 0 0 2.5px #35d357,
        0 2px 6px rgba(0, 0, 0, 0.5);
    }
    .badge.svelte-1j4lisl {
      border-color: #1f2937;
    }
  }


  /* Ties the popover to the button that opened it, matching MfmMenu's caret so
     the whole cluster reads the same way — including its direction: the base
     sits on the BUTTON and the apex meets this panel, so the taper names the
     source. `bottom` is set inline because it tracks the trigger while the
     panel itself may have been shifted down.

     9.5px = the 12px gap between the trigger and this menu, less the 2.5px
     `.is-on` ring MfmControlButton spreads outside the pill. Same derivation as
     `--mfm-caret-width` in MfmMenu.svelte, written out because this caret is
     positioned against a flex row rather than the panel. */
  .filter-menu-caret.svelte-o361wv {
    position: absolute;
    left: -9.5px;
    width: 0;
    height: 0;
    border-top: 6px solid transparent;
    border-bottom: 6px solid transparent;
    /* MfmControlButton's `.is-on` ring, so the caret reads as that ring growing
       a tail. Same colour pair as `.mfm-menu-caret` in MfmMenu.svelte. */
    border-left: 9.5px solid #2bbe4a;
  }

  html.dark .filter-menu-caret.svelte-o361wv {
    border-left-color: #35d357;
  }

  /* R3a's 44px tap-target minimum, carried over from the bottom-sheet B3/U10
     removed. The rows are py-2.5/text-[13px] (~38px), which is right for a
     mouse and short of the touch minimum; the sheet used to raise them via a
     `.sheet-body` wrapper that no longer exists.

     Re-scoped to the card at phone widths rather than dropped, because the
     requirement was never about the sheet — it was about fingers. Same 600px
     breakpoint the removed `isMobile` used, so the same viewports keep the same
     targets; the desktop popover's rows are untouched. Taller rows make the
     card taller, which U9's cap and this element's own `overflow-y-auto`
     already handle. */
  @media (max-width: 600px) {
    .filter-menu-card.svelte-o361wv button,
    .filter-menu-card.svelte-o361wv [role='button'],
    .filter-menu-card.svelte-o361wv input {
      min-height: 44px;
    }
    /* Icon-only controls (checkbox/chevron toggles) need the area too. */
    .filter-menu-card.svelte-o361wv button.h-6,
    .filter-menu-card.svelte-o361wv button.w-6 {
      min-width: 44px;
      min-height: 44px;
    }
  }

  /* U8 — AI-tagged pill: subtle dotted underline on the label so the
     user can distinguish "AI surfaced this for me" from "I toggled this". */
  .filter-ai-tagged.svelte-o361wv > span:where(.svelte-o361wv):last-child {
    text-decoration: underline dotted;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
    text-decoration-color: rgba(26, 115, 232, 0.45);
  }

  /* U8 — Pulse on newly-activated pill (~600ms). Svelte 5 auto-scopes
     both the @keyframes name and the matching `animation:` reference
     inside this style block, keeping them in sync without a manual
     :global() wrap. */
  @keyframes svelte-o361wv-filterActivatedPulse {
    0%   { box-shadow: 0 0 0 0 rgba(26, 115, 232, 0); }
    50%  { box-shadow: 0 0 0 4px rgba(26, 115, 232, 0.35); }
    100% { box-shadow: 0 0 0 0 rgba(26, 115, 232, 0); }
  }

  @media (prefers-reduced-motion: no-preference) {
    .filter-just-activated.svelte-o361wv {
      animation: svelte-o361wv-filterActivatedPulse 600ms ease-out;
    }
  }


  /* The hide notices' treatment, deliberately: a translucent pill over the map
     is what a passive-but-tappable notice looks like in this cluster, and the
     chip sits in the same column. What differs is the one thing that has to:
     the label WRAPS. */
  .wind-filter-chip.svelte-178c79g {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    max-width: 100%;
    min-width: 0;
    padding: 3px 4px 3px 10px;
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.94);
    color: #1f2937;
    font-size: 12px;
    line-height: 1.35;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
    backdrop-filter: blur(4px);
    pointer-events: auto;
  }

  .wind-filter-chip-label.svelte-178c79g {
    min-width: 0;
    /* The whole point (K-G): five long names in Hebrew do not fit one line at
       the bottom-sheet width, and a truncated direction is a wrong direction.
       No `text-overflow`, no `nowrap`. */
    white-space: normal;
    overflow-wrap: anywhere;
    /* A hair of top padding so the first line sits on the ×'s centreline while
       the last line is free to run past it. */
    padding-top: 6px;
  }

  .wind-filter-chip-clear.svelte-178c79g {
    position: relative;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: #5f6368;
    cursor: pointer;
  }

  .wind-filter-chip-clear.svelte-178c79g .material-symbols-outlined:where(.svelte-178c79g) {
    font-size: 18px;
  }

  /* 32px painted, 44px hit — `.mfm-hide-notice-action::after`'s rule, restated
     for the same WCAG 2.5.5 floor every control on this map holds.
     32 + 2*6 = 44. */
  .wind-filter-chip-clear.svelte-178c79g::after {
    content: '';
    position: absolute;
    inset: -6px;
  }

  .wind-filter-chip-clear.svelte-178c79g:hover {
    background: rgba(95, 99, 104, 0.12);
  }

  .wind-filter-chip-clear.svelte-178c79g:focus-visible {
    outline: 2px solid #1a73e8;
    outline-offset: 1px;
  }

  html.dark .wind-filter-chip.svelte-178c79g {
    background: rgba(31, 41, 55, 0.94);
    color: #f3f4f6;
  }

  html.dark .wind-filter-chip-clear.svelte-178c79g {
    color: #d1d5db;
  }

  html.dark .wind-filter-chip-clear.svelte-178c79g:hover {
    background: rgba(209, 213, 219, 0.15);
  }


  .mfm-controls-container.svelte-rpbn0u {
    position: absolute;
    left: 10px;
    /* This cluster owns the bottom-LEFT corner. Do NOT copy the map tools'
       180px resting height: that number exists to clear Google's native Street
       View and Camera controls, which are stacked under the map tools in
       whichever corner those two share (the bottom-RIGHT one, since the swap).
       This corner has nothing beneath it, so 40px clears the attribution strip
       and nothing else.

       The two vars are then added on top so the cluster never sits under the
       weather datetime bar or the expanded mobile AI sheet. Both publish 0 when
       absent, so the resting position is the 40px base.

       The AI term applies at every width — that sheet is full-bleed, so it is
       always underneath. The WEATHER term is not: `.weatherSliderOverlay` is a
       centred card, so on a wide map its near edge never reaches this cluster
       and the lift is pure dead space. Hence the indirection through
       --weather-clearance: this declaration is the collide-anyway default, and
       `weatherClearanceStyle` overrides it inline with 0px once the two
       provably cannot touch. (That predicate is side-agnostic — the bar is
       centred — so it needed no change when this cluster changed corners.) */
    --weather-clearance: var(--weather-overlay-h, 0px);
    bottom: max(40px, calc(40px + var(--weather-clearance, 0px) + var(--ai-bar-bottom-h, 0px)));
    /* U4 / item 6 — above `.weatherSliderOverlay` (z-index 5) so this cluster's
       menus and the map tools' FilterMenu both paint over the weather datetime
       bar. Deliberately NOT >= 1300: that would put it above the AI bottom
       sheet, which must stay on top of the map chrome. */
    z-index: 6;
    display: flex;
    flex-direction: column;
    /* ONE declaration of the cluster's own vertical rhythm. `.compact` retunes
       this var rather than `gap` itself, so `.mfm-hide-notices` below can hang
       each notice on its button's centreline by reading the same number — the
       two cannot drift, which is what the hard-coded 12px there used to do the
       moment `.compact` dropped the real gap to 8px. */
    --mfm-cluster-gap: 12px;
    gap: var(--mfm-cluster-gap);
    align-items: flex-start;
    transition:
      transform 0.3s ease-in-out, bottom 0.3s ease-in-out,
      left 0.3s ease-in-out, gap 0.3s ease-in-out;
  }

  /* The filter menu is positioned against this, not the container, so it tracks
     the button through both layouts. */
  .mfm-filter-wrapper.svelte-rpbn0u {
    position: relative;
  }

  /* ── B3/U5 + B3/U6 — the hide-gate notices (R1, R2) ───────────────────────
     Out of the flex flow in every layout (see the markup comment for the three
     reasons), stacked upward from the cluster's top edge so the pills keep
     their full touch targets and the container's measured width is unchanged.

     `max-width` rather than a fixed width: one notice is ~200px and two stack
     rather than share a line, so the cap only bites on a phone, where it makes
     the label ellipsise instead of pushing the pill past the map's edge. The
     `100vw - 20px` term is `MFM_INSET` at each side, matching `.compact`. */
  .mfm-hide-notices.svelte-rpbn0u {
    position: absolute;
    /* BESIDE the cluster, not above it. Stacked above, a notice about havens
       floated over the map with the Havens button below and to its left, and
       read as a banner about the map rather than as the label on the control
       that releases it. To the right of the column it sits alongside the pills
       it belongs to, in space that is empty map in this layout.
       `top: 0` rather than `bottom: 0`: the gated buttons (Filter, then Havens)
       are the top of the column, so the notices meet them there. */
    left: calc(100% + 8px);
    top: 0;
    /* The cluster's own vertical rhythm, restated so each notice can be placed
       on its button's centreline below. `--mfm-row-h` is MfmControlButton's box
       and `--mfm-row-gap` is this container's actual `gap` — keep all three in
       step, or the notices drift off their buttons by a row.

       It READS `--mfm-cluster-gap` rather than restating a number, which is the
       fix for exactly that drift: this was hard-coded 12px while `.compact`
       (every phone, in either orientation) laid the column out on 8px, so the
       second notice hung 4px below the Havens pill it labels. The phone-landscape
       column is `.compact`, so it is the layout that had the bug and the one
       these notices matter most in — they are the only escape from the two hide
       gates, and they are deliberately non-dismissible. */
    --mfm-row-h: 44px;
    --mfm-row-gap: var(--mfm-cluster-gap);
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    /* 12px, not the cluster's 6-8px: each notice's action button expands its
       hit area 6px beyond the pill (see `::after` below), so a smaller gap
       would overlap the two buttons' targets and hand a tap to the wrong
       gate. 6 + 6 = 12 makes them abut exactly. */
    gap: 12px;
    max-width: min(320px, calc(100vw - 20px));
    /* The wrapper is only a positioning box; letting it take pointer events
       would swallow map drags in the strip above the cluster. The pills take
       theirs back. */
    pointer-events: none;
  }

  /* The retired `.mfm-haven-hint`'s treatment, revived deliberately: a
     translucent white pill over the map is what a passive notice looks like in
     this cluster, and the reason A3/U9 retired it from
     `.mfm-control-button-caption` was that a caption is not tappable while a
     white pill reads as if it were. These ARE tappable. */
  /* Each notice on its own button's CENTRELINE (column layout only).
     `--mfm-row` is the button's index down the cluster: Filter leads it, then
     Havens. Selected on the testid rather than a modifier class so this stays a
     stylesheet-only concern — the markup that renders these is shared and
     deliberately untouched.

     `top` resolves to the row's centre and `translateY(-50%)` hangs the pill on
     it, so the notice tracks the button whatever the notice's own height. The
     two rows are 56px apart and the pill is ~38px, so both can show at once
     without meeting.

     Scoped away from `.is-row`, NOT from `.compact`: what makes a row index
     meaningless is the cluster being laid out horizontally, and `.compact` no
     longer says that. It was `:not(.compact)` while the two were the same
     answer; once phone landscape became a compact COLUMN, that selector could
     never match there — the layout that needs these offsets most would have
     been the one layout that never got them, and this file's own test scenario
     for them could not have passed. */
  .mfm-controls-container.svelte-rpbn0u:not(.is-row) .mfm-hide-notice:where(.svelte-rpbn0u) {
    position: absolute;
    top: calc(
      var(--mfm-row, 0) * (var(--mfm-row-h) + var(--mfm-row-gap)) + var(--mfm-row-h) / 2
    );
    transform: translateY(-50%);
    /* Taking the notices out of flow leaves the wrapper with no in-flow content,
       so it shrinks to zero width — and the pill's own `max-width: 100%` then
       resolves against zero, collapsing the label to nothing and leaving a bare
       icon and "Show again". Size to the content instead, and restate the cap
       against the VIEWPORT, which is what it was really protecting. */
    width: max-content;
    max-width: calc(100vw - var(--mfm-row-h) - 30px);
  }

  .mfm-hide-notice[data-testid='mfm-hide-notice-points'].svelte-rpbn0u { --mfm-row: 0; }
  .mfm-hide-notice[data-testid='mfm-hide-notice-havens'].svelte-rpbn0u { --mfm-row: 1; }

  /* The wind chip takes the row BELOW Havens, so all three can show at once
     without meeting. Same rule as the notices above, restated rather than
     shared because the chip's height is not fixed — its names wrap — and
     `translateY(-50%)` on a two-line pill hangs it on the same centreline
     whatever it grew to. Scoped away from `.compact` for the same reason the
     notices are: that layout is a horizontal row, where a row INDEX is not a
     vertical offset, and the chip keeps its stacked position. */
  .mfm-controls-container.svelte-rpbn0u:not(.compact) .mfm-wind-chip-slot:where(.svelte-rpbn0u) {
    position: absolute;
    --mfm-row: 2;
    top: calc(
      var(--mfm-row, 0) * (var(--mfm-row-h) + var(--mfm-row-gap)) + var(--mfm-row-h) / 2
    );
    transform: translateY(-50%);
    width: max-content;
    max-width: calc(100vw - var(--mfm-row-h) - 30px);
  }

  /* In `.compact` the notices stay in the wrapper's flex column, and so does
     the chip; it only needs the same width cap the column carries. */
  .mfm-wind-chip-slot.svelte-rpbn0u {
    max-width: 100%;
    min-width: 0;
  }

  .mfm-hide-notice.svelte-rpbn0u {
    display: flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    min-width: 0;
    padding: 3px 4px 3px 10px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.94);
    color: #1f2937;
    font-size: 12px;
    white-space: nowrap;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
    backdrop-filter: blur(4px);
    pointer-events: auto;
  }

  /* The label is the only part that may shrink — the icon and the escape
     button are fixed-size targets, exactly as in the retired hint. */
  .mfm-hide-notice-label.svelte-rpbn0u {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .mfm-hide-notice-action.svelte-rpbn0u {
    position: relative;
    flex: none;
    display: flex;
    align-items: center;
    min-height: 32px;
    padding: 0 10px;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: #1a73e8;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
  }

  /* 32px painted, 44px hit — the WCAG 2.5.5 floor every other control on this
     map holds, reached with an inset pseudo-element rather than by growing
     the pill to 44px tall (which would read as a button, not a notice).
     32 + 2*6 = 44. */
  .mfm-hide-notice-action.svelte-rpbn0u::after {
    content: '';
    position: absolute;
    inset: -6px -4px;
  }

  .mfm-hide-notice-action.svelte-rpbn0u:hover {
    background: rgba(26, 115, 232, 0.1);
  }

  .mfm-hide-notice-action.svelte-rpbn0u:focus-visible {
    outline: 2px solid #1a73e8;
    outline-offset: 1px;
  }

  html.dark .mfm-hide-notice.svelte-rpbn0u {
    background: rgba(31, 41, 55, 0.94);
    color: #f3f4f6;
  }

  html.dark .mfm-hide-notice-action.svelte-rpbn0u {
    color: #93c5fd;
  }

  html.dark .mfm-hide-notice-action.svelte-rpbn0u:hover {
    background: rgba(147, 197, 253, 0.15);
  }

  /* A3/U6 removed `.mfm-haven-hint` and its dark-theme block from here. Its
     translucent-pill-over-the-map treatment briefly lived on in
     `.mfm-control-button-caption` (MfmControlButton.svelte); A3/U9 retired
     that too — a white pill is a tappable affordance (R3) — and replaced it
     with a haloed white label. Nothing in this app carries the hint's
     treatment now. */

  /* Compact only tightens the spacing. It used to reflow to a horizontal row as
     well, which was wrong for the case that triggers it most: a portrait phone
     is NARROW, not short, and turning a 4-button column on its side there spends
     the one axis that is scarce to save the one that is not — and dropped the
     row on top of the full-width weather bar. */
  /* The menus have to paint OVER the map chrome on a landscape phone.
     `.mfm-menu-panel` already carries `z-[20]`, but it is sealed inside this
     container's own stacking context at `z-index: 6`, so 20 is only ever 20
     RELATIVE TO ITS SIBLINGS — against the chrome band (`z-mapchrome`, 100) the
     whole cluster is what competes, and it loses. Raising the container is what
     lifts the panel with it.

     Only while a menu is open, and only on a landscape phone: at rest the
     cluster must stay below the chrome so the chrome's own menus and the search
     dropdown keep winning over a row of buttons. 200 clears `z-mapchrome` and
     stays well under the AI sheet's 1300, which must keep covering the map
     chrome — the same ceiling the base `z-index: 6` rule argues for. */
  .mfm-controls-container.menu-over-chrome.svelte-rpbn0u {
    z-index: 200;
  }

  .mfm-controls-container.compact.svelte-rpbn0u {
    left: 10px;
    --mfm-cluster-gap: 8px;
    max-width: calc(100vw - 20px);
  }

  /* The ROW layout, for short viewports that are NOT landscape phones: a short
     desktop or tablet window, and a landscape phone wider than the 1023px bound
     `getIsPhoneLandscape()` carries. A landscape phone is a column instead — the
     weather bar gives up PHONE_LANDSCAPE_BAR_SIDE_RESERVE_PX at each end
     precisely so both columns can stand in the space it vacates, spending one
     band of a 390px-tall screen rather than three.

     The column DOES fit there, which is worth stating because the comment this
     replaces claimed it "does not fit above the fold at all": four 44px pills
     with three 8px gaps is 200px on the 40px base, topping out at 240px — clear
     of a ~60px chrome band on a 390px viewport by 90px, and on the stated 320px
     floor by ~20px. That claim predates Crew leaving the cluster (it was five
     buttons) and `.compact` dropping the gap from 12px to 8px.

     83px = the map tools' 35px base + their 40px button + an 8px gap: in this
     layout BOTH clusters are rows on the same band, so this one rides above.
     `--mfm-short-base` drops it back to the tools' own band when
     `clusterRowsWouldCollide` proves the two rows clear. */
  .mfm-controls-container.is-row.svelte-rpbn0u {
    bottom: max(
      var(--mfm-short-base, 83px),
      calc(var(--mfm-short-base, 83px) + var(--weather-clearance, 0px) + var(--ai-bar-bottom-h, 0px))
    );
    /* row-REVERSE, because this cluster is left-anchored. The rule is "whichever
       child sits at the bottom of the column sits nearest the corner in the
       row", and that child is the last one (AI). Left-anchored, last-first means
       reversing. Swapping the anchor without swapping this leaves the row
       mirrored end-for-end — which reads as nothing worse than odd button order,
       so it survives review easily. The map tools take the opposite value for
       exactly the same reason. Phone landscape stops being a row, but this rule
       still fires for the viewports listed above, so the direction argument has
       to survive the move off `.compact.short` intact. */
    flex-direction: row-reverse;
    align-items: center;
    flex-wrap: nowrap;
  }

  /* The ROW lays the cluster out along the bottom, where the space to its right
     is the map-tools cluster, not empty map. So the notices keep the original
     position above it in that layout — and only in that layout.

     Keyed on `.is-row`, not `.compact`, which is what it said before. Since
     `isCompact` is true for every phone, `.compact` matched the landscape-phone
     COLUMN too, and would have gone on stacking two ~38px notices above a 200px
     column: 240 + 8 + 84 ≈ 332px up a 390px-tall screen, under the chrome band,
     and off a 320px one outright. Migrating the `.compact.short` rules alone
     would not have touched this — it is keyed one class shallower, which is the
     whole trap. */
  .mfm-controls-container.is-row.svelte-rpbn0u .mfm-hide-notices:where(.svelte-rpbn0u) {
    left: 0;
    top: auto;
    bottom: calc(100% + 8px);
  }

  @media (prefers-reduced-motion: reduce) {
    .mfm-controls-container.svelte-rpbn0u {
      transition: none;
    }
  }



  .seamark-attribution.svelte-w23wtp {
    position: absolute;
    /* SEAMARK_ATTRIBUTION_LEFT_PX — 76px clears the Google logo: Google draws
       it ~66px wide with a ~5px inset in the bottom-left of each layer div,
       and the strip wants a few pixels of air after it. `seamarkCreditLayout`
       adds this same number (and the padding below) to the parts' widths. */
    left: 76px;
    /* Flush with the map's bottom edge, exactly like Google's copyright row
       on the right — no inset of its own. The mobile AI sheet lifts it
       through the same `--ai-bar-bottom-h` contract `.weatherSliderOverlay`
       uses: 0 when collapsed/hidden, unset on desktop → falls back to 0.
       Smooth so it follows the sheet's expand/collapse. Nothing else moves
       it but Google's own row (`.is-stacked` below): not the weather card
       (painted under, see z-index) and not a panel (the stack it lives in
       resizes instead). */
    bottom: var(--ai-bar-bottom-h, 0px);
    transition: bottom 0.3s ease-in-out;
    /* The same 14px row Google's `.gm-style-cc` is: 10px Roboto on a 14px
       line box, no vertical padding, clipped to that height so a fallback
       font's descenders cannot push it taller than Google's row. */
    max-height: 14px;
    box-sizing: border-box;
    /* SEAMARK_ATTRIBUTION_PAD_PX each side. */
    padding: 0 6px;
    /* Above the layer divs (Google's `.gm-style` root opens its own stacking
       context, so nothing inside the map can climb past a later sibling) AND
       above the weather datetime card (`.weatherSliderOverlay`, 5), the one
       piece of chrome the stacked strip can touch. Level with the mfm
       cluster (6), which never reaches this corner; the AI sheet (≥ 1300)
       stays above every piece of map chrome. */
    z-index: 6;
    /* Measured from Google's row: `.gm-style-cc` text is 10px on a 14px line
       in Roboto, Arial, sans-serif. Kept identical so the credit and
       "Map data ©…" read as one line. */
    font-family: Roboto, Arial, sans-serif;
    font-size: 10px;
    line-height: 14px;
    white-space: nowrap;
    overflow: hidden;
    background: rgba(255, 255, 255, 0.8);
    color: rgba(0, 0, 0, 0.7);
    /* The strip itself must never swallow a map drag; only the links are live. */
    pointer-events: none;
    user-select: none;
  }

  /* Google's row reaches this corner (phones; narrow maps on satellite):
     climb exactly one Google row (GOOGLE_CREDIT_ROW_H_PX) so the strip sits
     ON that row rather than over its text — the two still touch, no gap. */
  .seamark-attribution.is-stacked.svelte-w23wtp {
    bottom: calc(14px + var(--ai-bar-bottom-h, 0px));
  }

  /* Each part is an inline-block so it has a box `bind:offsetWidth` can
     watch — a ResizeObserver never reports a plain inline. Top-aligned so
     the boxes cannot open a baseline gap under the 14px line. */
  .seamark-attribution-link.svelte-w23wtp,
  .seamark-attribution-sep.svelte-w23wtp,
  .seamark-attribution-hint.svelte-w23wtp {
    display: inline-block;
    vertical-align: top;
  }
  /* The spaces around the middot are the separator's whole job; inside an
     inline-block the strip's `nowrap` would collapse them away. */
  .seamark-attribution-sep.svelte-w23wtp,
  .seamark-attribution-hint.svelte-w23wtp {
    white-space: pre;
  }

  /* OpenSeaMap's credit and its separator while both credits would run into
     Google's row. Out of flow — the strip shrinks to the credit left — but
     still laid out, so its width stays measurable and the decision that hid
     it cannot flip back (`display: none` would zero the measurement and
     oscillate). `visibility` also drops it from the accessibility tree and
     the tab order. */
  .seamark-attribution.svelte-w23wtp .is-hidden:where(.svelte-w23wtp) {
    position: absolute;
    visibility: hidden;
    pointer-events: none;
  }

  .seamark-attribution-link.svelte-w23wtp {
    pointer-events: auto;
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 2px;
  }
  .seamark-attribution-link.svelte-w23wtp:hover {
    color: #111827;
  }

  /* Follows the app's resolved theme (html.dark), the way the rest of the map
     chrome does — the same slate the map-control buttons and the weather bar
     use on dark. */
  html.dark .seamark-attribution.svelte-w23wtp {
    background: rgba(31, 41, 55, 0.85);
    color: #e5e7eb;
  }
  html.dark .seamark-attribution-link.svelte-w23wtp:hover {
    color: #ffffff;
  }

/*!
 * Quill Editor v2.0.3
 * https://quilljs.com
 * Copyright (c) 2017-2024, Slab
 * Copyright (c) 2014, Jason Chen
 * Copyright (c) 2013, salesforce.com
 */
.ql-container{box-sizing:border-box;font-family:Helvetica,Arial,sans-serif;font-size:13px;height:100%;margin:0;position:relative}.ql-container.ql-disabled .ql-tooltip{visibility:hidden}.ql-container:not(.ql-disabled) li[data-list=checked] > .ql-ui,.ql-container:not(.ql-disabled) li[data-list=unchecked] > .ql-ui{cursor:pointer}.ql-clipboard{left:-100000px;height:1px;overflow-y:hidden;position:absolute;top:50%}.ql-clipboard p{margin:0;padding:0}.ql-editor{box-sizing:border-box;counter-reset:list-0 list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;line-height:1.42;height:100%;outline:none;overflow-y:auto;padding:12px 15px;tab-size:4;-moz-tab-size:4;text-align:left;white-space:pre-wrap;word-wrap:break-word}.ql-editor > *{cursor:text}.ql-editor p,.ql-editor ol,.ql-editor pre,.ql-editor blockquote,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6{margin:0;padding:0}@supports (counter-set:none){.ql-editor p,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6{counter-set:list-0 list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor p,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6{counter-reset:list-0 list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor table{border-collapse:collapse}.ql-editor td{border:1px solid #000;padding:2px 5px}.ql-editor ol{padding-left:1.5em}.ql-editor li{list-style-type:none;padding-left:1.5em;position:relative}.ql-editor li > .ql-ui:before{display:inline-block;margin-left:-1.5em;margin-right:.3em;text-align:right;white-space:nowrap;width:1.2em}.ql-editor li[data-list=checked] > .ql-ui,.ql-editor li[data-list=unchecked] > .ql-ui{color:#777}.ql-editor li[data-list=bullet] > .ql-ui:before{content:'\2022'}.ql-editor li[data-list=checked] > .ql-ui:before{content:'\2611'}.ql-editor li[data-list=unchecked] > .ql-ui:before{content:'\2610'}@supports (counter-set:none){.ql-editor li[data-list]{counter-set:list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list]{counter-reset:list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered]{counter-increment:list-0}.ql-editor li[data-list=ordered] > .ql-ui:before{content:counter(list-0, decimal) '. '}.ql-editor li[data-list=ordered].ql-indent-1{counter-increment:list-1}.ql-editor li[data-list=ordered].ql-indent-1 > .ql-ui:before{content:counter(list-1, lower-alpha) '. '}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-1{counter-set:list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-1{counter-reset:list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-2{counter-increment:list-2}.ql-editor li[data-list=ordered].ql-indent-2 > .ql-ui:before{content:counter(list-2, lower-roman) '. '}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-2{counter-set:list-3 list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-2{counter-reset:list-3 list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-3{counter-increment:list-3}.ql-editor li[data-list=ordered].ql-indent-3 > .ql-ui:before{content:counter(list-3, decimal) '. '}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-3{counter-set:list-4 list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-3{counter-reset:list-4 list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-4{counter-increment:list-4}.ql-editor li[data-list=ordered].ql-indent-4 > .ql-ui:before{content:counter(list-4, lower-alpha) '. '}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-4{counter-set:list-5 list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-4{counter-reset:list-5 list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-5{counter-increment:list-5}.ql-editor li[data-list=ordered].ql-indent-5 > .ql-ui:before{content:counter(list-5, lower-roman) '. '}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-5{counter-set:list-6 list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-5{counter-reset:list-6 list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-6{counter-increment:list-6}.ql-editor li[data-list=ordered].ql-indent-6 > .ql-ui:before{content:counter(list-6, decimal) '. '}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-6{counter-set:list-7 list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-6{counter-reset:list-7 list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-7{counter-increment:list-7}.ql-editor li[data-list=ordered].ql-indent-7 > .ql-ui:before{content:counter(list-7, lower-alpha) '. '}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-7{counter-set:list-8 list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-7{counter-reset:list-8 list-9}}.ql-editor li[data-list=ordered].ql-indent-8{counter-increment:list-8}.ql-editor li[data-list=ordered].ql-indent-8 > .ql-ui:before{content:counter(list-8, lower-roman) '. '}@supports (counter-set:none){.ql-editor li[data-list].ql-indent-8{counter-set:list-9}}@supports not (counter-set:none){.ql-editor li[data-list].ql-indent-8{counter-reset:list-9}}.ql-editor li[data-list=ordered].ql-indent-9{counter-increment:list-9}.ql-editor li[data-list=ordered].ql-indent-9 > .ql-ui:before{content:counter(list-9, decimal) '. '}.ql-editor .ql-indent-1:not(.ql-direction-rtl){padding-left:3em}.ql-editor li.ql-indent-1:not(.ql-direction-rtl){padding-left:4.5em}.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right{padding-right:3em}.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right{padding-right:4.5em}.ql-editor .ql-indent-2:not(.ql-direction-rtl){padding-left:6em}.ql-editor li.ql-indent-2:not(.ql-direction-rtl){padding-left:7.5em}.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right{padding-right:6em}.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right{padding-right:7.5em}.ql-editor .ql-indent-3:not(.ql-direction-rtl){padding-left:9em}.ql-editor li.ql-indent-3:not(.ql-direction-rtl){padding-left:10.5em}.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right{padding-right:9em}.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right{padding-right:10.5em}.ql-editor .ql-indent-4:not(.ql-direction-rtl){padding-left:12em}.ql-editor li.ql-indent-4:not(.ql-direction-rtl){padding-left:13.5em}.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right{padding-right:12em}.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right{padding-right:13.5em}.ql-editor .ql-indent-5:not(.ql-direction-rtl){padding-left:15em}.ql-editor li.ql-indent-5:not(.ql-direction-rtl){padding-left:16.5em}.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right{padding-right:15em}.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right{padding-right:16.5em}.ql-editor .ql-indent-6:not(.ql-direction-rtl){padding-left:18em}.ql-editor li.ql-indent-6:not(.ql-direction-rtl){padding-left:19.5em}.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right{padding-right:18em}.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right{padding-right:19.5em}.ql-editor .ql-indent-7:not(.ql-direction-rtl){padding-left:21em}.ql-editor li.ql-indent-7:not(.ql-direction-rtl){padding-left:22.5em}.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right{padding-right:21em}.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right{padding-right:22.5em}.ql-editor .ql-indent-8:not(.ql-direction-rtl){padding-left:24em}.ql-editor li.ql-indent-8:not(.ql-direction-rtl){padding-left:25.5em}.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right{padding-right:24em}.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right{padding-right:25.5em}.ql-editor .ql-indent-9:not(.ql-direction-rtl){padding-left:27em}.ql-editor li.ql-indent-9:not(.ql-direction-rtl){padding-left:28.5em}.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right{padding-right:27em}.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right{padding-right:28.5em}.ql-editor li.ql-direction-rtl{padding-right:1.5em}.ql-editor li.ql-direction-rtl > .ql-ui:before{margin-left:.3em;margin-right:-1.5em;text-align:left}.ql-editor table{table-layout:fixed;width:100%}.ql-editor table td{outline:none}.ql-editor .ql-code-block-container{font-family:monospace}.ql-editor .ql-video{display:block;max-width:100%}.ql-editor .ql-video.ql-align-center{margin:0 auto}.ql-editor .ql-video.ql-align-right{margin:0 0 0 auto}.ql-editor .ql-bg-black{background-color:#000}.ql-editor .ql-bg-red{background-color:#e60000}.ql-editor .ql-bg-orange{background-color:#f90}.ql-editor .ql-bg-yellow{background-color:#ff0}.ql-editor .ql-bg-green{background-color:#008a00}.ql-editor .ql-bg-blue{background-color:#06c}.ql-editor .ql-bg-purple{background-color:#93f}.ql-editor .ql-color-white{color:#fff}.ql-editor .ql-color-red{color:#e60000}.ql-editor .ql-color-orange{color:#f90}.ql-editor .ql-color-yellow{color:#ff0}.ql-editor .ql-color-green{color:#008a00}.ql-editor .ql-color-blue{color:#06c}.ql-editor .ql-color-purple{color:#93f}.ql-editor .ql-font-serif{font-family:Georgia,Times New Roman,serif}.ql-editor .ql-font-monospace{font-family:Monaco,Courier New,monospace}.ql-editor .ql-size-small{font-size:.75em}.ql-editor .ql-size-large{font-size:1.5em}.ql-editor .ql-size-huge{font-size:2.5em}.ql-editor .ql-direction-rtl{direction:rtl;text-align:inherit}.ql-editor .ql-align-center{text-align:center}.ql-editor .ql-align-justify{text-align:justify}.ql-editor .ql-align-right{text-align:right}.ql-editor .ql-ui{position:absolute}.ql-editor.ql-blank::before{color:rgba(0,0,0,0.6);content:attr(data-placeholder);font-style:italic;left:15px;pointer-events:none;position:absolute;right:15px}.ql-snow.ql-toolbar:after,.ql-snow .ql-toolbar:after{clear:both;content:'';display:table}.ql-snow.ql-toolbar button,.ql-snow .ql-toolbar button{background:none;border:none;cursor:pointer;display:inline-block;float:left;height:24px;padding:3px 5px;width:28px}.ql-snow.ql-toolbar button svg,.ql-snow .ql-toolbar button svg{float:left;height:100%}.ql-snow.ql-toolbar button:active:hover,.ql-snow .ql-toolbar button:active:hover{outline:none}.ql-snow.ql-toolbar input.ql-image[type=file],.ql-snow .ql-toolbar input.ql-image[type=file]{display:none}.ql-snow.ql-toolbar button:hover,.ql-snow .ql-toolbar button:hover,.ql-snow.ql-toolbar button:focus,.ql-snow .ql-toolbar button:focus,.ql-snow.ql-toolbar button.ql-active,.ql-snow .ql-toolbar button.ql-active,.ql-snow.ql-toolbar .ql-picker-label:hover,.ql-snow .ql-toolbar .ql-picker-label:hover,.ql-snow.ql-toolbar .ql-picker-label.ql-active,.ql-snow .ql-toolbar .ql-picker-label.ql-active,.ql-snow.ql-toolbar .ql-picker-item:hover,.ql-snow .ql-toolbar .ql-picker-item:hover,.ql-snow.ql-toolbar .ql-picker-item.ql-selected,.ql-snow .ql-toolbar .ql-picker-item.ql-selected{color:#06c}.ql-snow.ql-toolbar button:hover .ql-fill,.ql-snow .ql-toolbar button:hover .ql-fill,.ql-snow.ql-toolbar button:focus .ql-fill,.ql-snow .ql-toolbar button:focus .ql-fill,.ql-snow.ql-toolbar button.ql-active .ql-fill,.ql-snow .ql-toolbar button.ql-active .ql-fill,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-fill,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-fill,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-fill,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-fill,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-fill,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-fill,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-fill,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-fill,.ql-snow.ql-toolbar button:hover .ql-stroke.ql-fill,.ql-snow .ql-toolbar button:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar button:focus .ql-stroke.ql-fill,.ql-snow .ql-toolbar button:focus .ql-stroke.ql-fill,.ql-snow.ql-toolbar button.ql-active .ql-stroke.ql-fill,.ql-snow .ql-toolbar button.ql-active .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill{fill:#06c}.ql-snow.ql-toolbar button:hover .ql-stroke,.ql-snow .ql-toolbar button:hover .ql-stroke,.ql-snow.ql-toolbar button:focus .ql-stroke,.ql-snow .ql-toolbar button:focus .ql-stroke,.ql-snow.ql-toolbar button.ql-active .ql-stroke,.ql-snow .ql-toolbar button.ql-active .ql-stroke,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke,.ql-snow.ql-toolbar button:hover .ql-stroke-miter,.ql-snow .ql-toolbar button:hover .ql-stroke-miter,.ql-snow.ql-toolbar button:focus .ql-stroke-miter,.ql-snow .ql-toolbar button:focus .ql-stroke-miter,.ql-snow.ql-toolbar button.ql-active .ql-stroke-miter,.ql-snow .ql-toolbar button.ql-active .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke-miter,.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter,.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter{stroke:#06c}@media (pointer:coarse){.ql-snow.ql-toolbar button:hover:not(.ql-active),.ql-snow .ql-toolbar button:hover:not(.ql-active){color:#444}.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-fill,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-fill,.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill{fill:#444}.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke,.ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter,.ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter{stroke:#444}}.ql-snow{box-sizing:border-box}.ql-snow *{box-sizing:border-box}.ql-snow .ql-hidden{display:none}.ql-snow .ql-out-bottom,.ql-snow .ql-out-top{visibility:hidden}.ql-snow .ql-tooltip{position:absolute;transform:translateY(10px)}.ql-snow .ql-tooltip a{cursor:pointer;text-decoration:none}.ql-snow .ql-tooltip.ql-flip{transform:translateY(-10px)}.ql-snow .ql-formats{display:inline-block;vertical-align:middle}.ql-snow .ql-formats:after{clear:both;content:'';display:table}.ql-snow .ql-stroke{fill:none;stroke:#444;stroke-linecap:round;stroke-linejoin:round;stroke-width:2}.ql-snow .ql-stroke-miter{fill:none;stroke:#444;stroke-miterlimit:10;stroke-width:2}.ql-snow .ql-fill,.ql-snow .ql-stroke.ql-fill{fill:#444}.ql-snow .ql-empty{fill:none}.ql-snow .ql-even{fill-rule:evenodd}.ql-snow .ql-thin,.ql-snow .ql-stroke.ql-thin{stroke-width:1}.ql-snow .ql-transparent{opacity:.4}.ql-snow .ql-direction svg:last-child{display:none}.ql-snow .ql-direction.ql-active svg:last-child{display:inline}.ql-snow .ql-direction.ql-active svg:first-child{display:none}.ql-snow .ql-editor h1{font-size:2em}.ql-snow .ql-editor h2{font-size:1.5em}.ql-snow .ql-editor h3{font-size:1.17em}.ql-snow .ql-editor h4{font-size:1em}.ql-snow .ql-editor h5{font-size:.83em}.ql-snow .ql-editor h6{font-size:.67em}.ql-snow .ql-editor a{text-decoration:underline}.ql-snow .ql-editor blockquote{border-left:4px solid #ccc;margin-bottom:5px;margin-top:5px;padding-left:16px}.ql-snow .ql-editor code,.ql-snow .ql-editor .ql-code-block-container{background-color:#f0f0f0;border-radius:3px}.ql-snow .ql-editor .ql-code-block-container{margin-bottom:5px;margin-top:5px;padding:5px 10px}.ql-snow .ql-editor code{font-size:85%;padding:2px 4px}.ql-snow .ql-editor .ql-code-block-container{background-color:#23241f;color:#f8f8f2;overflow:visible}.ql-snow .ql-editor img{max-width:100%}.ql-snow .ql-picker{color:#444;display:inline-block;float:left;font-size:14px;font-weight:500;height:24px;position:relative;vertical-align:middle}.ql-snow .ql-picker-label{cursor:pointer;display:inline-block;height:100%;padding-left:8px;padding-right:2px;position:relative;width:100%}.ql-snow .ql-picker-label::before{display:inline-block;line-height:22px}.ql-snow .ql-picker-options{background-color:#fff;display:none;min-width:100%;padding:4px 8px;position:absolute;white-space:nowrap}.ql-snow .ql-picker-options .ql-picker-item{cursor:pointer;display:block;padding-bottom:5px;padding-top:5px}.ql-snow .ql-picker.ql-expanded .ql-picker-label{color:#ccc;z-index:2}.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-fill{fill:#ccc}.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-stroke{stroke:#ccc}.ql-snow .ql-picker.ql-expanded .ql-picker-options{display:block;margin-top:-1px;top:100%;z-index:1}.ql-snow .ql-color-picker,.ql-snow .ql-icon-picker{width:28px}.ql-snow .ql-color-picker .ql-picker-label,.ql-snow .ql-icon-picker .ql-picker-label{padding:2px 4px}.ql-snow .ql-color-picker .ql-picker-label svg,.ql-snow .ql-icon-picker .ql-picker-label svg{right:4px}.ql-snow .ql-icon-picker .ql-picker-options{padding:4px 0}.ql-snow .ql-icon-picker .ql-picker-item{height:24px;width:24px;padding:2px 4px}.ql-snow .ql-color-picker .ql-picker-options{padding:3px 5px;width:152px}.ql-snow .ql-color-picker .ql-picker-item{border:1px solid transparent;float:left;height:16px;margin:2px;padding:0;width:16px}.ql-snow .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg{position:absolute;margin-top:-9px;right:0;top:50%;width:18px}.ql-snow .ql-picker.ql-header .ql-picker-label[data-label]:not([data-label=''])::before,.ql-snow .ql-picker.ql-font .ql-picker-label[data-label]:not([data-label=''])::before,.ql-snow .ql-picker.ql-size .ql-picker-label[data-label]:not([data-label=''])::before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-label]:not([data-label=''])::before,.ql-snow .ql-picker.ql-font .ql-picker-item[data-label]:not([data-label=''])::before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-label]:not([data-label=''])::before{content:attr(data-label)}.ql-snow .ql-picker.ql-header{width:98px}.ql-snow .ql-picker.ql-header .ql-picker-label::before,.ql-snow .ql-picker.ql-header .ql-picker-item::before{content:'Normal'}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before{content:'Heading 1'}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before{content:'Heading 2'}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before{content:'Heading 3'}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before{content:'Heading 4'}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before{content:'Heading 5'}.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before{content:'Heading 6'}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before{font-size:2em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before{font-size:1.5em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before{font-size:1.17em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before{font-size:1em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before{font-size:.83em}.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before{font-size:.67em}.ql-snow .ql-picker.ql-font{width:108px}.ql-snow .ql-picker.ql-font .ql-picker-label::before,.ql-snow .ql-picker.ql-font .ql-picker-item::before{content:'Sans Serif'}.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=serif]::before,.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before{content:'Serif'}.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=monospace]::before,.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before{content:'Monospace'}.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before{font-family:Georgia,Times New Roman,serif}.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before{font-family:Monaco,Courier New,monospace}.ql-snow .ql-picker.ql-size{width:98px}.ql-snow .ql-picker.ql-size .ql-picker-label::before,.ql-snow .ql-picker.ql-size .ql-picker-item::before{content:'Normal'}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=small]::before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before{content:'Small'}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=large]::before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before{content:'Large'}.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=huge]::before,.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before{content:'Huge'}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before{font-size:10px}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before{font-size:18px}.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before{font-size:32px}.ql-snow .ql-color-picker.ql-background .ql-picker-item{background-color:#fff}.ql-snow .ql-color-picker.ql-color .ql-picker-item{background-color:#000}.ql-code-block-container{position:relative}.ql-code-block-container .ql-ui{right:5px;top:5px}.ql-toolbar.ql-snow{border:1px solid #ccc;box-sizing:border-box;font-family:'Helvetica Neue','Helvetica','Arial',sans-serif;padding:8px}.ql-toolbar.ql-snow .ql-formats{margin-right:15px}.ql-toolbar.ql-snow .ql-picker-label{border:1px solid transparent}.ql-toolbar.ql-snow .ql-picker-options{border:1px solid transparent;box-shadow:rgba(0,0,0,0.2) 0 2px 8px}.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-label{border-color:#ccc}.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-options{border-color:#ccc}.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item.ql-selected,.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item:hover{border-color:#000}.ql-toolbar.ql-snow + .ql-container.ql-snow{border-top:0}.ql-snow .ql-tooltip{background-color:#fff;border:1px solid #ccc;box-shadow:0 0 5px #ddd;color:#444;padding:5px 12px;white-space:nowrap}.ql-snow .ql-tooltip::before{content:"Visit URL:";line-height:26px;margin-right:8px}.ql-snow .ql-tooltip input[type=text]{display:none;border:1px solid #ccc;font-size:13px;height:26px;margin:0;padding:3px 5px;width:170px}.ql-snow .ql-tooltip a.ql-preview{display:inline-block;max-width:200px;overflow-x:hidden;text-overflow:ellipsis;vertical-align:top}.ql-snow .ql-tooltip a.ql-action::after{border-right:1px solid #ccc;content:'Edit';margin-left:16px;padding-right:8px}.ql-snow .ql-tooltip a.ql-remove::before{content:'Remove';margin-left:8px}.ql-snow .ql-tooltip a{line-height:26px}.ql-snow .ql-tooltip.ql-editing a.ql-preview,.ql-snow .ql-tooltip.ql-editing a.ql-remove{display:none}.ql-snow .ql-tooltip.ql-editing input[type=text]{display:inline-block}.ql-snow .ql-tooltip.ql-editing a.ql-action::after{border-right:0;content:'Save';padding-right:0}.ql-snow .ql-tooltip[data-mode=link]::before{content:"Enter link:"}.ql-snow .ql-tooltip[data-mode=formula]::before{content:"Enter formula:"}.ql-snow .ql-tooltip[data-mode=video]::before{content:"Enter video:"}.ql-snow a{color:#06c}.ql-container.ql-snow{border:1px solid #ccc}

/*# sourceMappingURL=quill.snow.css.map*/
  .quill-wrapper.svelte-10unq2k {
    background: white;
    position: relative;
  }

  .editor-header.svelte-10unq2k {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 10;
  }

  .expand-btn.svelte-10unq2k {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border: 1px solid #e5e7eb;
    border-radius: 4px;
    background: white;
    cursor: pointer;
    color: #6b7280;
    transition: all 0.15s;
  }

  .expand-btn.svelte-10unq2k:hover {
    background: #f3f4f6;
    color: #374151;
  }

  .expand-btn.svelte-10unq2k .material-symbols-outlined:where(.svelte-10unq2k) {
    font-size: 18px;
  }

  /* Image upload feedback. An upload that fails has to SAY so: the old
     behaviour never failed because it silently inlined the bytes. */
  .image-status.svelte-10unq2k,
  .image-error.svelte-10unq2k {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 8px;
    margin: 0;
    padding: 8px 12px;
    font-size: 13px;
    line-height: 1.4;
  }

  .image-status.svelte-10unq2k {
    color: #4b5563;
    background: #f3f4f6;
  }

  .image-error.svelte-10unq2k {
    color: #991b1b;
    background: #fef2f2;
    border-top: 1px solid #fecaca;
  }

  .dismiss-btn.svelte-10unq2k {
    flex: none;
    border: none;
    background: transparent;
    color: inherit;
    font-size: 16px;
    line-height: 1;
    cursor: pointer;
    padding: 0 2px;
  }

  .quill-wrapper.svelte-10unq2k .ql-container {
    min-height: 150px;
    font-size: 14px;
  }

  .quill-wrapper.svelte-10unq2k .ql-editor {
    min-height: 150px;
  }

  /* The 'uploading-image' placeholder embed (quillImageUpload.ts). Unscoped
     — :global — so it renders identically in the modal editor's own
     `.ql-editor`, not just the inline one. Never persisted: normalizeQuillHtml
     strips this node before it can reach the bound `value`. */
  .ql-uploading-image {
    display: inline-block;
    padding: 2px 8px;
    border: 1px dashed #9ca3af;
    border-radius: 4px;
    background: #f3f4f6;
    color: #6b7280;
    font-size: 0.85em;
    font-style: italic;
    user-select: none;
  }

  .quill-wrapper.svelte-10unq2k .ql-toolbar {
    border-top-left-radius: 0.5rem;
    border-top-right-radius: 0.5rem;
    background: #f9fafb;
  }

  .quill-wrapper.svelte-10unq2k .ql-container {
    border-bottom-left-radius: 0.5rem;
    border-bottom-right-radius: 0.5rem;
  }

  /* Modal styles */
  .modal-backdrop.svelte-10unq2k {
    position: fixed;
    inset: 0;
    background: rgba(55, 65, 81, 0.6);
    backdrop-filter: blur(4px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10000;
    padding: 16px;
  }

  @media (min-width: 640px) {
    .modal-backdrop.svelte-10unq2k {
      padding: 24px;
    }
  }

  @media (min-width: 1024px) {
    .modal-backdrop.svelte-10unq2k {
      padding-left: 288px;
      padding-top: 80px;
    }
  }

  .modal-content.svelte-10unq2k {
    background: white;
    border-radius: 12px;
    width: 100%;
    max-width: 42rem; /* max-w-2xl */
    height: 85vh;
    display: flex;
    flex-direction: column;
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
  }

  @media (min-width: 1024px) {
    .modal-content.svelte-10unq2k {
      max-width: 64rem; /* max-w-5xl */
    }
  }

  .modal-header.svelte-10unq2k {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 20px;
    border-bottom: 1px solid #e5e7eb;
  }

  .modal-header.svelte-10unq2k h3:where(.svelte-10unq2k) {
    margin: 0;
    font-size: 18px;
    font-weight: 600;
    color: #111827;
  }

  .close-btn.svelte-10unq2k {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: none;
    border-radius: 6px;
    background: transparent;
    cursor: pointer;
    color: #6b7280;
    font-size: 24px;
    line-height: 1;
    transition: all 0.15s;
  }

  .close-btn.svelte-10unq2k:hover {
    background: #f3f4f6;
    color: #374151;
  }

  .modal-editor.svelte-10unq2k {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }

  .modal-editor.svelte-10unq2k .ql-toolbar {
    border-left: none;
    border-right: none;
    border-top: none;
    background: #f9fafb;
  }

  .modal-editor.svelte-10unq2k .ql-container {
    flex: 1;
    border: none;
    font-size: 16px;
    overflow-y: auto;
  }

  .modal-editor.svelte-10unq2k .ql-editor {
    padding: 20px 24px;
    min-height: 100%;
  }

  /* Dark theme. Quill's snow theme is light-only — #444 icons, white picker
     and tooltip surfaces, #ccc borders — and gives the editor no text colour
     at all, so in dark mode the page's light body text landed on this
     wrapper's white background. The surface mirrors the editor's other
     inputs (app.css base layer: gray-800 field, gray-200 text, gray-600
     border, gray-400 placeholder); toolbar and tooltips sit one step up on
     gray-700, and active controls use the dark link blue (blue-400). */
  html.dark .quill-surface.svelte-10unq2k,
  html.dark .modal-content.svelte-10unq2k {
    background: #1f2937;
  }

  html.dark .quill-surface.svelte-10unq2k .ql-toolbar,
  html.dark .quill-surface.svelte-10unq2k .ql-tooltip {
    background: #374151;
  }

  html.dark .quill-surface.svelte-10unq2k .ql-toolbar.ql-snow,
  html.dark .quill-surface.svelte-10unq2k .ql-container.ql-snow,
  html.dark .quill-surface.svelte-10unq2k .ql-picker.ql-expanded .ql-picker-label,
  html.dark .quill-surface.svelte-10unq2k .ql-picker.ql-expanded .ql-picker-options,
  html.dark .quill-surface.svelte-10unq2k .ql-tooltip,
  html.dark .quill-surface.svelte-10unq2k .ql-tooltip input[type="text"] {
    border-color: #4b5563;
  }

  html.dark .quill-surface.svelte-10unq2k .ql-editor,
  html.dark .quill-surface.svelte-10unq2k .ql-tooltip {
    color: #e5e7eb;
  }

  html.dark .quill-surface.svelte-10unq2k .ql-editor.ql-blank::before {
    color: #9ca3af;
  }

  /* Authored colours are chosen against a white page — pasted text routinely
     pins `color: rgb(64, 64, 64)` or a white background — and read as
     dark-on-dark here. Same treatment as the POI panel's dark mode
     (InfoPanel.svelte, `.poi-about *`), so the editor previews what a
     dark-mode reader actually sees. */
  html.dark .quill-surface.svelte-10unq2k .ql-editor [style],
  html.dark .quill-surface.svelte-10unq2k .ql-editor [class*="ql-color-"],
  html.dark .quill-surface.svelte-10unq2k .ql-editor [class*="ql-bg-"] {
    color: inherit !important;
    background-color: transparent !important;
  }

  html.dark .quill-surface.svelte-10unq2k .ql-editor a,
  html.dark .quill-surface.svelte-10unq2k .ql-tooltip a {
    color: #60a5fa;
  }

  html.dark .quill-surface.svelte-10unq2k .ql-editor code {
    background-color: #111827;
  }

  html.dark .quill-surface.svelte-10unq2k .ql-editor blockquote {
    border-left-color: #4b5563;
  }

  /* Toolbar icons and picker labels. */
  html.dark .quill-surface.svelte-10unq2k .ql-picker {
    color: #d1d5db;
  }

  html.dark .quill-surface.svelte-10unq2k .ql-stroke,
  html.dark .quill-surface.svelte-10unq2k .ql-stroke-miter {
    stroke: #d1d5db;
  }

  html.dark .quill-surface.svelte-10unq2k .ql-fill,
  html.dark .quill-surface.svelte-10unq2k .ql-stroke.ql-fill {
    fill: #d1d5db;
  }

  html.dark .quill-surface.svelte-10unq2k .ql-picker-options {
    background-color: #1f2937;
  }

  html.dark .quill-surface.svelte-10unq2k .ql-color-picker .ql-picker-item.ql-selected,
  html.dark .quill-surface.svelte-10unq2k .ql-color-picker .ql-picker-item:hover {
    border-color: #f3f4f6;
  }

  html.dark .quill-surface.svelte-10unq2k .ql-toolbar button:hover,
  html.dark .quill-surface.svelte-10unq2k .ql-toolbar button:focus,
  html.dark .quill-surface.svelte-10unq2k .ql-toolbar button.ql-active,
  html.dark .quill-surface.svelte-10unq2k .ql-toolbar .ql-picker-label:hover,
  html.dark .quill-surface.svelte-10unq2k .ql-toolbar .ql-picker-label.ql-active,
  html.dark .quill-surface.svelte-10unq2k .ql-toolbar .ql-picker-item:hover,
  html.dark .quill-surface.svelte-10unq2k .ql-toolbar .ql-picker-item.ql-selected {
    color: #60a5fa;
  }

  html.dark .quill-surface.svelte-10unq2k .ql-toolbar button:hover .ql-stroke,
  html.dark .quill-surface.svelte-10unq2k .ql-toolbar button:focus .ql-stroke,
  html.dark .quill-surface.svelte-10unq2k .ql-toolbar button.ql-active .ql-stroke,
  html.dark .quill-surface.svelte-10unq2k .ql-toolbar .ql-picker-label:hover .ql-stroke,
  html.dark .quill-surface.svelte-10unq2k .ql-toolbar .ql-picker-label.ql-active .ql-stroke,
  html.dark .quill-surface.svelte-10unq2k .ql-toolbar button:hover .ql-stroke-miter,
  html.dark .quill-surface.svelte-10unq2k .ql-toolbar button.ql-active .ql-stroke-miter {
    stroke: #60a5fa;
  }

  html.dark .quill-surface.svelte-10unq2k .ql-toolbar button:hover .ql-fill,
  html.dark .quill-surface.svelte-10unq2k .ql-toolbar button:focus .ql-fill,
  html.dark .quill-surface.svelte-10unq2k .ql-toolbar button.ql-active .ql-fill,
  html.dark .quill-surface.svelte-10unq2k .ql-toolbar .ql-picker-label:hover .ql-fill,
  html.dark .quill-surface.svelte-10unq2k .ql-toolbar .ql-picker-label.ql-active .ql-fill {
    fill: #60a5fa;
  }

  /* This component's own chrome. */
  html.dark .expand-btn.svelte-10unq2k {
    border-color: #4b5563;
    background: #1f2937;
    color: #d1d5db;
  }

  html.dark .expand-btn.svelte-10unq2k:hover,
  html.dark .close-btn.svelte-10unq2k:hover {
    background: #374151;
    color: #f3f4f6;
  }

  html.dark .close-btn.svelte-10unq2k {
    color: #d1d5db;
  }

  html.dark .modal-header.svelte-10unq2k {
    border-bottom-color: #374151;
  }

  html.dark .modal-header.svelte-10unq2k h3:where(.svelte-10unq2k) {
    color: #f3f4f6;
  }

  html.dark .image-status.svelte-10unq2k {
    color: #d1d5db;
    background: #374151;
  }

  html.dark .image-error.svelte-10unq2k {
    color: #fecaca;
    background: rgb(127 29 29 / 40%);
    border-top-color: #7f1d1d;
  }

  html.dark .ql-uploading-image {
    border-color: #6b7280;
    background: #374151;
    color: #d1d5db;
  }


  .fullscreen-overlay.svelte-y0h6bt {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.8);
    display: flex;
    justify-content: center;
    align-items: center;
  }

  .fullscreen-content.svelte-y0h6bt {
    position: relative;
    padding: 0;
    border-radius: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width:100%;
    height: 100%;
  }

  .close-button.svelte-y0h6bt {
    position: fixed;
    top: 0;
    right: 12px;
    background: none;
    border: none;
    font-size: 48px;
    color: white;
    cursor: pointer;
    border-radius: 50%;
  }

  .fullscreen-content.svelte-y0h6bt img:where(.svelte-y0h6bt) {
    width: 100%;
    height: 100%;
    object-fit: contain;
  }

  .nav-button.svelte-y0h6bt {
    position: fixed;
    top: 50%;
    transform: translateY(-50%);
    background: rgba(0, 0, 0, 0.5);
    color: white;
    border: none;
    padding: 10px 15px;
    cursor: pointer;
    font-size: 2em;
    border-radius: 5px;
    z-index: 1201;
  }

  .nav-button.left.svelte-y0h6bt {
    left: 10px;
  }

  .nav-button.right.svelte-y0h6bt {
    right: 10px;
  }

  .source-details.svelte-y0h6bt {
    position:fixed;
    bottom:12px;
    left:6px;
    background:rgba(255, 255, 255, 0.8);
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 12px;
    color: #555;
    font-family: "Open Sans", sans-serif;
  }

  .source-details.svelte-y0h6bt a:where(.svelte-y0h6bt) {
    color: #007bff;
    text-decoration: none;
  }

  .source-details.svelte-y0h6bt a:where(.svelte-y0h6bt):hover {
    text-decoration: underline;
  }


  .scrollbar-thin.svelte-1fq5gm6::-webkit-scrollbar {
    height: 6px;
  }
  .scrollbar-thin.svelte-1fq5gm6::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 3px;
  }
  .scrollbar-thin.svelte-1fq5gm6::-webkit-scrollbar-thumb {
    background: #ccc;
    border-radius: 3px;
  }
  .scrollbar-thin.svelte-1fq5gm6::-webkit-scrollbar-thumb:hover {
    background: #aaa;
  }

  @media (hover: none) {
    .hover-fallback.svelte-1fq5gm6 {
      opacity: 1 !important;
    }
  }


  .place-details-container.svelte-alp3zm {
    min-height: 60px;
  }

  .place-details-container.svelte-alp3zm gmp-place-details-compact {
    width: 100%;
    --gmp-place-details-compact-background: white;
  }


  /* The source and both translations are Quill HTML, where bullets AND
     numbering are `<ol>` items told apart only by `data-list` (Quill draws
     the marker inside its own `.ql-editor`), and Tailwind's preflight strips
     list markers. Same rules as `.poi-about` in InfoPanel.css — without them
     this preview could not show whether a list survived translation. */
  .translation-html.svelte-sir75l ol,
  .translation-html.svelte-sir75l ul {
    padding-inline-start: 1.5em;
  }

  .translation-html.svelte-sir75l ul > li,
  .translation-html.svelte-sir75l li[data-list="bullet"] {
    list-style-type: disc;
  }

  .translation-html.svelte-sir75l ol > li:not([data-list]),
  .translation-html.svelte-sir75l li[data-list="ordered"] {
    list-style-type: decimal;
  }


  

  gmp-advanced-marker:has(> .selected-marker) {
    z-index: 1000;
  }

  .custom-advanced-marker {
    position: relative;
    transition: transform 0.1s ease-in-out;
    transform:translateY(20px);
    transform-origin: center;
    user-select: none;
  }

  .draft-dot {
    position: absolute;
    top: -2px;
    right: -2px;
    width: 10px;
    height: 10px;
    background-color: #ef4444;
    border-radius: 50%;
    border: 1.5px solid white;
    pointer-events: none;
  }

  .recommended-crown {
    position: absolute;
    top: -5px;
    left: 50%;
    transform: translateX(-50%);
    width: 22px;
    height: 10px;
    pointer-events: none;
    filter: drop-shadow(0 1px 1px rgba(0,0,0,0.2));
  }

  /* Unverified pin: render the dedicated _unverified.svg sprite at the same
     28 × 24 (40 × 34 when full-size) box used by verified markers so the
     dashed disc matches their outer radius — see icon CSS above for the
     defaults that this rule deliberately leaves untouched. The dashed
     stroke and shaded fill live in the SVG itself; no extra masks here. */

  .custom-advanced-marker.selected-marker {
    transform:translateY(20px) scale(1.5);
  }

  /* One-shot confirmation for "Show on map", which opens no panel. Animates a
     halo via box-shadow rather than transform: the selected-marker rule above
     owns `transform`, and animating it here would fight that scale. */
  @keyframes svelte-7sr3kz-mfm-reveal-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(43, 190, 74, 0.75); }
    70%  { box-shadow: 0 0 0 18px rgba(43, 190, 74, 0); }
    100% { box-shadow: 0 0 0 0 rgba(43, 190, 74, 0); }
  }

  .custom-advanced-marker.revealed-marker {
    border-radius: 50%;
    animation: svelte-7sr3kz-mfm-reveal-pulse 1.1s ease-out 2;
  }

  /* Respect a reduced-motion preference: the pulse is pure confirmation, so
     dropping it costs nothing that the selected scale does not already say. */
  @media (prefers-reduced-motion: reduce) {
    .custom-advanced-marker.revealed-marker {
      animation: none;
    }
  }

  .plus-icon-overlay {
    position: absolute;
    background-color: white;
    border-radius: 50%;
    cursor: pointer;
    transform: translate(-50%, -50%);
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 6px rgba(0,0,0,0.3);
    user-select: none;
  }

  .plus-icon-overlay .material-symbols-outlined {
    font-size: 24px;
    color: #1a73e8;
  }

  .navigational-point-overlay {
    position: absolute;
    width: 18px;
    height: 18px;
    background-color: #6666cc;
    border: 2px solid white;
    border-radius: 50%;
    transform: translate(-50%, -50%);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
    cursor: grab;
    transition: transform 0.1s ease-in-out;
    user-select: none;
  }

  .navigational-point-overlay:hover {
    transform: translate(-50%, -50%) scale(1.2);
  }

  .navigational-point-overlay.selected-nav-point {
    transform: translate(-50%, -50%) scale(1.5);
    z-index: 1000;
  }

  .nav-point-delete-button {
    position: absolute;
    width: 20px;
    height: 20px;
    background-color: #d32f2f;
    border: 2px solid white;
    border-radius: 50%;
    transform: translate(-50%, -50%);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1001;
    transition: background-color 0.15s ease;
    user-select: none;
  }

  .nav-point-delete-button:hover {
    background-color: #b71c1c;
  }

  .nav-point-delete-button .material-symbols-outlined {
    font-size: 14px;
    color: white;
  }

  .clicked-location-marker {
    width: 14px;
    height: 14px;
    background-color: #4285F4;
    border: 2px solid white;
    border-radius: 50%;
    box-shadow: 0 0 4px rgba(0,0,0,0.4);
    cursor: grab;
    user-select: none;
  }

  .distance-label {
    position: absolute;
    background: rgba(255, 255, 255, 0.8);
    padding: 2px 5px;
    border-radius: 3px;
    font-size: 12px;
    font-weight: 500;
    transform: translate(-50%, -50%);
    white-space: nowrap;
  }

  .custom-advanced-marker img.advanced-marker-icon {
    display: block;
    width: 28px;
    height: 24px;
  }

  /* Full-size markers for POI types (zoom 12-16) when zoomed to 17+ */
  .custom-advanced-marker.marker-full-size img.advanced-marker-icon {
    width: 40px;
    height: 34px;
  }

  /* ── Occluded-marker dots ──────────────────────────────────────────────
     A marker that loses the 24px occlusion contest keeps its position and
     renders as a 4px disc in its own category colour instead of vanishing.
     Design: docs/superpowers/specs/2026-08-03-occluded-marker-dots-design.md

     Every rule is scoped under .mapWrapper.occlusion-dots (same pattern as
     .ai-build-hiding-pois below) so that with the feature off the ::after
     below is never created — otherwise every marker on the map would carry a
     pseudo-element for a feature that is not running.

     --occlusion-dot-color and --occlusion-dot-y are published per marker by
     createMarker, read from the marker's own sprite. The fallbacks here cover
     markers whose art is outside the sprite set (external iconUrl) and the
     window before the sprite parse resolves. 46% is the midpoint of the three
     real disc centres (44.07% / 48% / 50%), i.e. the least-wrong constant —
     which is exactly why the real value is derived rather than hardcoded. */
  /* One source of truth for the dot<->pin timing: it drives four transitions
     across three rules, and at 180ms the grow/collapse was over before the eye
     could pick it up — the markers just appeared to snap. Custom properties
     inherit, and every marker is a descendant of .mapWrapper, so the value
     reaches all of them. */
  .mapWrapper.occlusion-dots.svelte-7sr3kz {
    --occlusion-dot-anim: 500ms;
  }

  .mapWrapper.occlusion-dots.svelte-7sr3kz .custom-advanced-marker img.advanced-marker-icon {
    /* The pin shrinks toward the dot's centre rather than the box's, which is
       what makes the two read as one object growing and collapsing. */
    transform-origin: 50% var(--occlusion-dot-y, 46%);
    transition:
      transform var(--occlusion-dot-anim, 500ms) ease-out,
      opacity var(--occlusion-dot-anim, 500ms) ease-out;
  }

  /* 0.33 ≈ 6px ÷ ~18px, the rendered diameter of the sprite's coloured disc, so
     the shrinking pin lands on the dot's size rather than near it. A single
     constant despite the two sprite families implying 0.357 and 0.321: the
     image is fully transparent by the time it reaches this scale, so only the
     ORIGIN above is visually load-bearing. Keep in step with the dot's
     width/height below. */
  .mapWrapper.occlusion-dots.svelte-7sr3kz .custom-advanced-marker.occluded-dot img.advanced-marker-icon {
    transform: scale(0.33);
    opacity: 0;
  }

  /* Every child that is NOT the pin image fades out in the dot state.
     Stated as the complement of the one element that must animate, rather than
     as a list of the decorations that must not: the crown, the draft badge and
     the weather score pill are all absolutely positioned siblings that would
     otherwise hang at full size around a 4px dot, and the pill in particular is
     appended imperatively by the weather effect (see PILL_ATTR above) — a rule
     naming each class by hand would silently miss it, and miss the next one. */
  .mapWrapper.occlusion-dots.svelte-7sr3kz .custom-advanced-marker > *:not(img.advanced-marker-icon) {
    transition: opacity var(--occlusion-dot-anim, 500ms) ease-out;
  }

  /* `!important` is load-bearing here, not laziness. The weather status pill
     (WeatherScorePill.ts) sets `opacity:0.9` as an INLINE style, and its
     'loading' variant additionally animates opacity through the Web Animations
     API. A normal stylesheet declaration loses to both; an important author
     declaration outranks inline-normal styles AND animations, so it is the only
     form that actually hides them. Without it the no-score and still-loading
     havens keep a full-size grey pill hovering over a 6px dot — which is what
     made demoted markers look like locations that should not be on the map. */
  .mapWrapper.occlusion-dots.svelte-7sr3kz .custom-advanced-marker.occluded-dot > *:not(img.advanced-marker-icon) {
    opacity: 0 !important;
  }

  .mapWrapper.occlusion-dots.svelte-7sr3kz .custom-advanced-marker::after {
    content: '';
    position: absolute;
    left: 50%;
    top: var(--occlusion-dot-y, 46%);
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--occlusion-dot-color, #6b7280);
    /* No ring and no shadow: at this size either one eats most of the disc and
       swamps the category colour it exists to show. */
    transform: translate(-50%, -50%) scale(0);
    opacity: 0;
    transition:
      transform var(--occlusion-dot-anim, 500ms) ease-out,
      opacity var(--occlusion-dot-anim, 500ms) ease-out;
    pointer-events: none;
  }

  .mapWrapper.occlusion-dots.svelte-7sr3kz .custom-advanced-marker.occluded-dot::after {
    transform: translate(-50%, -50%) scale(1);
    opacity: 1;
  }

  /* Decorative only — a dot must never take a click from the pin that
     occluded it. */
  .mapWrapper.occlusion-dots.svelte-7sr3kz .custom-advanced-marker.occluded-dot {
    pointer-events: none;
  }

  @media (prefers-reduced-motion: reduce) {
    .mapWrapper.occlusion-dots.svelte-7sr3kz .custom-advanced-marker img.advanced-marker-icon,
    .mapWrapper.occlusion-dots.svelte-7sr3kz .custom-advanced-marker > *:not(img.advanced-marker-icon),
    .mapWrapper.occlusion-dots.svelte-7sr3kz .custom-advanced-marker::after {
      transition: none;
    }
  }

  /* U6: weather time-slider + cadence overlay, pinned to the bottom-centre of the
     map. Sits above the map tiles; the rest of the map stays interactive. */
  .weatherSliderOverlay.svelte-7sr3kz {
    position: absolute;
    /* Sit above the mobile AI bottom bar when it's visible: the bar publishes
       its occupied height as --ai-bar-bottom-h (0 when collapsed/hidden, unset
       on desktop → falls back to 0). Smooth so it follows the bar's expand/
       collapse. */
    bottom: calc(16px + var(--ai-bar-bottom-h, 0px));
    /* `translate` and `opacity` join the list for R10 (see `.panel-held`
       below): the hold has to animate on the SAME 0.3s ease curve
       `.mapContainerStack` resizes on, or the counter-translation lags the edge
       it is cancelling and the bar drifts anyway. `bottom` keeps its own
       ease-in-out — it tracks the AI bar, not the stack. */
    transition: bottom 0.3s ease-in-out, translate 0.3s ease, opacity 0.3s ease;
    left: 50%;
    transform: translateX(-50%);
    z-index: 5;
    /* 780 rather than 660: the Show/Hide PILLS (Batch 3 follow-up) are wider
       than the checkboxes they replaced (~280px for the pair against ~180),
       and at 660 they wrapped onto a second header row even on a wide desktop.
       780 fits title + cadence + the "updated …" note + both pills on the
       first row; `calc(100% - 32px)` still caps it on anything narrower, where
       the header wraps exactly as before (the 470px container query below is
       untouched). */
    width: min(780px, calc(100% - 32px));
    /* Container queries below size the header off the PANEL's own width (not the
       viewport), so the "updated …" note and the word "weather" drop only when this
       panel actually lacks the room. */
    container-type: inline-size;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    /* No inner gap/padding: the header is its own tinted bar and the night
       bands below it fill edge-to-edge down to the panel bottom. overflow:hidden
       clips both to the rounded corners. */
    gap: 0;
    padding: 0;
    border-radius: 12px;
    overflow: hidden;
    background: rgba(255, 255, 255, 0.92);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28), 0 2px 6px rgba(0, 0, 0, 0.16);
    backdrop-filter: blur(4px);
    pointer-events: auto;
  }
  html.dark .weatherSliderOverlay.svelte-7sr3kz {
    background: rgba(31, 41, 55, 0.92);
  }

  /* U4 / R2 — phone landscape narrows the bar so a vertical button column
     clears it on EACH side.

     132 is 2 x PHONE_LANDSCAPE_BAR_SIDE_RESERVE_PX from `mfmClusterLayout.ts`,
     where the 66 is derived from the hungrier corner's inset + button width
     plus CLEARANCE_GAP rather than picked. CSS cannot import a TypeScript
     constant, so nothing compiles the two together: `weatherOverlayNote.test.ts`
     imports the constant and asserts this declaration against it, and that
     assertion is the only thing keeping them in step. Move one, move the other.

     Expressed on the bar's OWN width on purpose. The bar is
     `container-type: inline-size`, so the header's 610/530/470/330px container
     queries re-fire off this value by themselves — no viewport media query
     belongs in the header, and its internal layout is unchanged. */
  .weatherSliderOverlay.phone-landscape.svelte-7sr3kz {
    width: min(780px, calc(100% - 132px));
  }

  /* ── R10: the bar holds its VISUAL position through a panel transition ──
     ONE invariant — the bar never moves from where the user sees it — but two
     rules, because the two orientations drag it in opposite directions.

     The obstacle is that the bar lives INSIDE `.mapContainerStack`, which is
     what a panel resizes: in portrait the stack loses height and the bar, hung
     off its bottom edge, rides that edge upward for 300ms and then blinks out;
     in landscape the stack loses width and the bar, centred on `left: 50%`,
     drifts left as the map's midline moves. Both are the bug this rule exists
     to prevent, not a cosmetic nicety.

     LANDSCAPE is the subtler half and the comment here twice said otherwise:
     the bar's width is `min(780px, calc(100% - 132px))` OF THE STACK, so while
     that `calc` branch wins the left edge is pinned one reserve from the
     stack's left edge and the bar holds itself — `--weather-bar-hold-x` is 0
     and the fade is the whole effect. It is only above a 912px stack, where the
     780px cap binds and the bar becomes genuinely centre-anchored, that the
     edge moves at all; there the variable carries exactly that difference. See
     `weatherBarHoldOffsets` for both wrong answers this replaced.

     So the bar counter-translates by exactly what the stack took, per axis, on
     the stack's own curve — `--weather-bar-hold-y` is the full sheet height in
     portrait, `--weather-bar-hold-x` half the drawer width in landscape (see
     `weatherBarHoldOffsets`). The individual `translate` property is used
     rather than folding this into `transform` so the existing
     `transform: translateX(-50%)` centring survives untouched; losing it would
     un-centre the bar outright.

     This is reachable ONLY through `.panel-held` / `.panel-releasing`, which
     only a phone ever gets. A desktop bar must keep taking its horizontal
     anchor from the stack, which is the whole point of `--side-panel-w`.

     Landscape additionally FADES: it holds still and disappears by opacity
     across the transition, while the two button clusters DO move in that same
     window (the map tools slide left to clear the drawer, which is correct and
     is deliberately not suppressed — only the bar is held). Portrait does not
     fade: it holds, then hard-hides once the panel has finished opening. */
  .weatherSliderOverlay.panel-held.svelte-7sr3kz {
    translate: var(--weather-bar-hold-x, 0px) var(--weather-bar-hold-y, 0px);
  }

  .weatherSliderOverlay.panel-held.phone-landscape.svelte-7sr3kz {
    opacity: 0;
  }

  /* The close direction cannot use the transition above: the bar has already
     left the DOM by then and REMOUNTS at the start of the close transition (R10
     wants it back before that transition begins, at the position it will rest
     at). A freshly mounted element has no previous computed value to transition
     from, so it would simply render at the released position and then drift as
     the stack grew back. A keyframe animation does run from its `from` on the
     element's first frame, which is exactly what is needed here. */
  @keyframes svelte-7sr3kz-weatherBarHoldRelease {
    from { translate: var(--weather-bar-hold-x, 0px) var(--weather-bar-hold-y, 0px); }
    to { translate: 0 0; }
  }

  @keyframes svelte-7sr3kz-weatherBarHoldReleaseFade {
    from {
      translate: var(--weather-bar-hold-x, 0px) var(--weather-bar-hold-y, 0px);
      opacity: 0;
    }
    to {
      translate: 0 0;
      opacity: 1;
    }
  }

  .weatherSliderOverlay.panel-releasing.svelte-7sr3kz {
    animation: svelte-7sr3kz-weatherBarHoldRelease 0.3s ease;
  }

  /* The symmetric reading of "disappear by changing opacity": landscape fades
     back IN over the close transition, again without moving. Stated rather than
     asked, and cheap to flip — drop this rule and landscape hard-shows like
     portrait. */
  .weatherSliderOverlay.panel-releasing.phone-landscape.svelte-7sr3kz {
    animation: svelte-7sr3kz-weatherBarHoldReleaseFade 0.3s ease;
  }

  @media (prefers-reduced-motion: reduce) {
    /* The counter-translation stays. It is not decoration: it is what CANCELS
       the movement `.mapContainerStack`'s own (unguarded) width/height
       transition would otherwise impart to the bar, so freezing it here would
       CREATE motion rather than remove it. Only the fade — which is decoration
       — is dropped, leaving landscape with portrait's hard cut. */
    .weatherSliderOverlay.svelte-7sr3kz {
      transition: bottom 0.3s ease-in-out, translate 0.3s ease;
    }

    /* Dropping `opacity` from the transition list above is not enough on its
       own: `.panel-held.phone-landscape { opacity: 0 }` then applies with no
       transition, so the bar VANISHED on the first frame of the hold — earlier
       than portrait, not the same as it. "Portrait's hard cut" means staying
       visible for the hold and leaving at the end, which is what the phase
       machine already does, so landscape must simply decline the fade. */
    .weatherSliderOverlay.panel-held.phone-landscape.svelte-7sr3kz {
      opacity: 1;
    }

    .weatherSliderOverlay.panel-releasing.phone-landscape.svelte-7sr3kz {
      animation: svelte-7sr3kz-weatherBarHoldRelease 0.3s ease;
    }
  }
  .weatherOverlayHeader.svelte-7sr3kz {
    align-self: stretch;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: 8px;
    /* row-gap 0: the mobile two-row split's only vertical gap is the break line's
       own height (below), so the phantom break line can't double the row spacing. */
    row-gap: 0;
    /* Positioning context for the ✕, which is pinned to this corner rather than
       flowing with the rest of the row — see .weatherOverlayClose. */
    position: relative;
    /* The right padding reserves the ✕'s column (10px edge + 22px button + 6px
       breathing room) so no wrapped row can ever run underneath it. */
    padding: 6px 38px 6px 10px;
    background: #f1f5f9; /* slate-100 — distinct title-bar tint vs the panel */
    border-bottom: 1px solid rgba(0, 0, 0, 0.08);
    -webkit-user-select: none;
    user-select: none;
  }
  html.dark .weatherOverlayHeader.svelte-7sr3kz {
    background: #374151; /* gray-700 */
    border-bottom-color: rgba(255, 255, 255, 0.08);
  }
  /* The cadence segmented control sits inline in the header sequence
     (title · "worst in:" · cadence · "updated hourly • last …" · ✕), keeping its
     natural width; the header wraps on narrow screens. */
  .weatherOverlayCadence.svelte-7sr3kz {
    display: flex;
    align-items: center;
  }
  /* Info link — Batch 3 moved both instances INSIDE their overlay pills (see
     .weatherOverlayPill below), which now inherit the pill's color; this base
     rule keeps the box, hit area and glyph sizing. */
  .weatherOverlayInfo.svelte-7sr3kz {
    flex: none;
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    /* Fully rounded, like the pill it sits in — the hover fill is a circle. */
    border-radius: 9999px;
    color: #6b7280;
    text-decoration: none;
    cursor: pointer;
  }
  .weatherOverlayInfo.svelte-7sr3kz .material-symbols-outlined:where(.svelte-7sr3kz) {
    font-size: 18px;
    line-height: 1;
  }
  /* ~44px touch target without affecting layout (outdoor mobile use). */
  .weatherOverlayInfo.svelte-7sr3kz::after {
    content: '';
    position: absolute;
    inset: -11px;
  }
  .weatherOverlayInfo.svelte-7sr3kz:hover {
    background: rgba(0, 0, 0, 0.06);
    color: #111827;
  }
  html.dark .weatherOverlayInfo.svelte-7sr3kz {
    color: #9ca3af;
  }
  html.dark .weatherOverlayInfo.svelte-7sr3kz:hover {
    background: rgba(255, 255, 255, 0.1);
    color: #f3f4f6;
  }
  .weatherOverlayTitle.svelte-7sr3kz {
    font-size: 13px;
    font-weight: 600;
    color: #111827; /* gray-900 */
  }
  .weatherOverlayNote.svelte-7sr3kz {
    font-size: 11px;
    font-weight: 400;
    color: #6b7280; /* gray-500 */
  }
  /* Desktop: the "updated …" note + toggles sit between the cadence and the ✕ — two
     auto left-margins (here + on .weatherOverlayClose) split the free space equally.
     Stacked on two tight lines ("updated hourly" / "last 07:18") so the note costs
     about half the row width it did inline, which is what buys room for the toggles. */
  .weatherOverlayUpdated.svelte-7sr3kz {
    margin-left: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    line-height: 1.15;
    text-align: center;
    white-space: nowrap;
    /* The note is the TALLEST item in this flex row (measured: 25.3px, against
       24px for the cadence control), so it — not the cadence buttons — sets the
       header height. Swapping its two lines for the 14px spinner therefore
       shrank the header by 1.3px and grew it back on every fetch. Reserving the
       two-line height keeps the row still: font-size × line-height × 2 lines,
       written as the arithmetic so it tracks the two values above. */
    min-height: calc(11px * 1.15 * 2);
  }
  /* The note's loading state: a small spinner in place of the two-line text,
     sized to sit inside the same row without growing the header. */
  .weatherOverlaySpinner.svelte-7sr3kz {
    font-size: 14px;
    line-height: 1;
    color: #6b7280; /* gray-500, matches .weatherOverlayNote's text colour */
  }
  html.dark .weatherOverlaySpinner.svelte-7sr3kz {
    color: #9ca3af; /* gray-400, matches the dark-mode note colour */
  }
  /* U4 — the note's failure state. Two lines like the settled state ("couldn't
     load forecast" / "Retry"), so it lands inside the height
     .weatherOverlayUpdated already reserves and the header does not jump. */
  .weatherOverlayFailed.svelte-7sr3kz {
    color: #b91c1c; /* red-700, matching the weather error banner in MfmControls */
  }
  html.dark .weatherOverlayFailed.svelte-7sr3kz {
    color: #fca5a5; /* red-300 */
  }
  .weatherOverlayRetry.svelte-7sr3kz {
    padding: 0;
    border: none;
    background: transparent;
    font: inherit;
    line-height: inherit;
    color: #b91c1c;
    text-decoration: underline;
    cursor: pointer;
  }
  .weatherOverlayRetry.svelte-7sr3kz:hover {
    color: #7f1d1d; /* red-900 */
  }
  html.dark .weatherOverlayRetry.svelte-7sr3kz {
    color: #fca5a5;
  }
  html.dark .weatherOverlayRetry.svelte-7sr3kz:hover {
    color: #fecaca; /* red-200 */
  }
  .spinning.svelte-7sr3kz {
    animation: svelte-7sr3kz-spin 1s linear infinite;
  }
  @keyframes svelte-7sr3kz-spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
  }
  /* The Scores / Beaufort-zones checkboxes, ending the first row.
     Its auto left-margin is the SECOND of exactly two in the row (the other is on the
     note): free space splits evenly between them, so the note sits the same distance
     from the cadence control as from the Scores checkbox. The ✕ is not part of this
     arithmetic — it is absolutely positioned in the header corner, and the header's
     reserved right padding is what keeps this group clear of it. When the note is
     hidden on narrow panels this auto is the only one left and the toggles still
     travel to the right edge. */
  .weatherOverlayToggles.svelte-7sr3kz {
    flex: none;
    margin-left: auto;
    display: flex;
    align-items: center;
    column-gap: 8px;
  }
  /* Batch 3 — the SHOW/HIDE pills that replaced the two checkboxes. The pill
     itself is the colored rounded rectangle; its two interactive children (the
     toggle button and the info link) sit flat inside it, so the info button is
     visually INSIDE the pill without nesting interactive elements. Filled
     while the overlay is on, tinted while off — the label carries the action
     ("Show …" / "Hide …"), the fill carries the state. */
  .weatherOverlayPill.svelte-7sr3kz {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 2px 4px 2px 0;
    border-radius: 9999px;
    white-space: nowrap;
  }
  .weatherOverlayPillMain.svelte-7sr3kz {
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: 11px;
    font-weight: 600;
    padding: 2px 6px 2px 8px;
    cursor: pointer;
    border-radius: 9999px 0 0 9999px;
    /* Review finding — a hairline seam before the info icon, so the pill
       visibly contains TWO targets and a click near its right edge is not a
       surprise info-panel open. On the button's flat right edge (the radius
       above rounds only the left), so it renders straight; currentColor at
       low opacity keeps it legible on both the filled and tinted states. */
    border-right: 1px solid color-mix(in srgb, currentColor 30%, transparent);
  }
  /* The VIBRANT fill belongs to the "Show …" state (overlay off): that is the
     invitation, so it carries the saturated call-to-action color; once the
     overlay is on, the pill reads "Hide …" and drops to the quiet tint —
     the map itself is now showing the color. (This is the reverse of the
     first cut, flipped on direct product direction.)

     Scores — the blue the old checkbox's accent-color already used. */
  .weatherOverlayPillScores.svelte-7sr3kz {
    background: #2563eb; /* blue-600 */
    color: #fff;
  }
  .weatherOverlayPillScores.is-on.svelte-7sr3kz {
    background: #dbeafe; /* blue-100 */
    color: #1d4ed8; /* blue-700 */
  }
  /* Beaufort zones — violet, so the two pills read as two different overlays
     at a glance rather than two states of one control. Violet rather than a
     wind-scale hue (green/amber/red) on purpose: the zones themselves paint
     the map in the wind scale, and a pill wearing one of those colors would
     read as a wind strength rather than as a control. */
  .weatherOverlayPillZones.svelte-7sr3kz {
    background: #7c3aed; /* violet-600 */
    color: #fff;
  }
  .weatherOverlayPillZones.is-on.svelte-7sr3kz {
    background: #ede9fe; /* violet-100 */
    color: #6d28d9; /* violet-700 */
  }
  html.dark .weatherOverlayPillScores.svelte-7sr3kz {
    background: #2563eb;
    color: #fff;
  }
  html.dark .weatherOverlayPillScores.is-on.svelte-7sr3kz {
    background: rgba(37, 99, 235, 0.25);
    color: #93c5fd; /* blue-300 */
  }
  html.dark .weatherOverlayPillZones.svelte-7sr3kz {
    background: #7c3aed;
    color: #fff;
  }
  html.dark .weatherOverlayPillZones.is-on.svelte-7sr3kz {
    background: rgba(124, 58, 237, 0.3);
    color: #c4b5fd; /* violet-300 */
  }
  /* The info link inside a pill inherits the pill's color in both states —
     the base rule's grey would vanish against the filled state. */
  .weatherOverlayPill.svelte-7sr3kz .weatherOverlayInfo:where(.svelte-7sr3kz) {
    color: inherit;
  }
  .weatherOverlayPill.svelte-7sr3kz .weatherOverlayInfo:where(.svelte-7sr3kz):hover {
    background: rgba(0, 0, 0, 0.12);
    color: inherit;
  }
  html.dark .weatherOverlayPill.svelte-7sr3kz .weatherOverlayInfo:where(.svelte-7sr3kz),
  html.dark .weatherOverlayPill.svelte-7sr3kz .weatherOverlayInfo:where(.svelte-7sr3kz):hover {
    color: inherit;
  }

  /* The no-zones note's toggle — sized like the info button beside it, and
     inheriting the pill's state color the same way. */
  .weatherOverlayZonesNoteBtn.svelte-7sr3kz {
    flex: none;
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border: 0;
    padding: 0;
    background: transparent;
    border-radius: 9999px;
    color: inherit;
    cursor: pointer;
  }
  .weatherOverlayZonesNoteBtn.svelte-7sr3kz .material-symbols-outlined:where(.svelte-7sr3kz) {
    font-size: 18px;
    line-height: 1;
  }
  /* Dismissed-but-relevant: while the note is hidden its button wears the
     pill's "Show …" call-to-action fill (the zones-off violet), so the way
     back to the explanation stands out against the quiet is-on tint around
     it — same invitation language as the pills themselves. Same values in
     dark mode, which also fills its "Show" state with violet-600/white. */
  .weatherOverlayZonesNoteBtn.note-hidden.svelte-7sr3kz {
    background: #7c3aed; /* violet-600 */
    color: #fff;
  }
  /* ~44px touch target without affecting layout, like the info button's. */
  .weatherOverlayZonesNoteBtn.svelte-7sr3kz::after {
    content: '';
    position: absolute;
    inset: -11px;
  }
  .weatherOverlayZonesNoteBtn.svelte-7sr3kz:hover {
    background: rgba(0, 0, 0, 0.12);
  }
  html.dark .weatherOverlayZonesNoteBtn.svelte-7sr3kz:hover {
    background: rgba(255, 255, 255, 0.1);
  }

  /* ── The "no Beaufort zone warnings here" row ──────────────────────────────
     The panel's first in-flow row, above the header and the datetime strip.
     In-flow, never absolutely positioned outside the panel: the panel is
     `overflow: hidden`, which clips a hung-outside toast to nothing (found
     the hard way in the browser), and in-flow it joins the measured panel
     height for free. Violet-tinted to read as the zones overlay's voice,
     matching .weatherOverlayPillZones. */
  .weatherZonesEmptyNote.svelte-7sr3kz {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    padding: 6px 8px 6px 12px;
    background: rgba(124, 58, 237, 0.08);
    border-bottom: 1px solid rgba(124, 58, 237, 0.2);
    font-size: 12px;
    line-height: 1.45;
    color: #374151;
  }
  .weatherZonesEmptyNoteText.svelte-7sr3kz {
    min-width: 0;
  }
  .weatherZonesEmptyNoteLink.svelte-7sr3kz {
    border: 0;
    padding: 0;
    background: transparent;
    color: #6d28d9;
    font: inherit;
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 2px;
    cursor: pointer;
  }
  .weatherZonesEmptyNoteLink.svelte-7sr3kz:hover {
    color: #5b21b6;
  }
  .weatherZonesEmptyNoteClose.svelte-7sr3kz {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border: 0;
    padding: 0;
    background: transparent;
    border-radius: 9999px;
    color: #6b7280;
    font-size: 12px;
    cursor: pointer;
  }
  .weatherZonesEmptyNoteClose.svelte-7sr3kz:hover {
    background: rgba(0, 0, 0, 0.06);
    color: #111827;
  }
  html.dark .weatherZonesEmptyNote.svelte-7sr3kz {
    background: rgba(124, 58, 237, 0.18);
    border-bottom-color: rgba(196, 181, 253, 0.25);
    color: #e5e7eb;
  }
  html.dark .weatherZonesEmptyNoteLink.svelte-7sr3kz {
    color: #c4b5fd;
  }
  html.dark .weatherZonesEmptyNoteLink.svelte-7sr3kz:hover {
    color: #ddd6fe;
  }
  html.dark .weatherZonesEmptyNoteClose.svelte-7sr3kz {
    color: #9ca3af;
  }
  html.dark .weatherZonesEmptyNoteClose.svelte-7sr3kz:hover {
    background: rgba(255, 255, 255, 0.1);
    color: #f3f4f6;
  }
  html.dark .weatherOverlayPill.svelte-7sr3kz .weatherOverlayInfo:where(.svelte-7sr3kz):hover {
    background: rgba(255, 255, 255, 0.18);
  }
  /* The pills' info links sit 22px tall inside a ~24px pill; their ::after
     hit-area extension (below) still provides the ~44px touch target. */
  /* ── U28 (R38, R39) — the note row ───────────────────────────────────────
     `flex-basis: 100%` makes it its own row at EVERY width by construction, so
     no breakpoint has to put it there and none can accidentally pull it back up
     beside the toggles. It stays inside the header's box (including the 38px
     right padding that reserves the ✕'s column), so the pinned ✕ never lands on
     top of the prose. */
  .weatherOverlayNoteRow.svelte-7sr3kz {
    flex-basis: 100%;
    margin: 0;
    padding-top: 4px;
    /* U8 / R6 — "a larger font that fills the row".
       Fluid against the PANEL, not the viewport: `.weatherSliderOverlay` already
       declares `container-type: inline-size` for the degrade ladder below, so
       `cqi` (1% of the panel's inline size) is the unit that already describes
       this row's real constraint. A fixed size cannot both fill a 660px panel and
       fit a 343px one; a viewport unit would ignore that the panel stops growing
       at 660 and would keep inflating on a wide desktop.

       The numbers: the full sentence measures ~40× the font size, against
       `container − 48px` of usable width (the header's padding plus the ✕'s
       reserved column). At the 660px cap that is 2.2cqi ≈ 14.5px and ~581px of
       text in 612px of room — the row fills, which is what R6 asks for. The 15px
       ceiling is therefore never reached at the current cap; it is there so a
       wider panel does not keep scaling.

       The 12px floor is the load-bearing end. It sets where the prose stops
       fitting on one line (40 × 12 + 48 = 528px of panel), which is why the note
       row's degrade breakpoint below is 530 and no longer shares the toggles' 470
       — raising the font without moving that threshold would have left a band of
       panel widths showing two-line prose. */
    font-size: clamp(12px, 2.2cqi, 15px);
    line-height: 1.35;
    color: #6b7280; /* gray-500 — the weight .weatherOverlayNote already uses */
  }
  html.dark .weatherOverlayNoteRow.svelte-7sr3kz {
    color: #9ca3af;
  }
  /* The three controls. Buttons rather than anchors: each opens a dialog in
     place, there is no URL behind them, and a bare <a href="#"> would offer a
     right-click menu full of dead options. Reset to look like the running text
     they sit inside, so the full-width row reads as one sentence. */
  .weatherOverlayNoteLink.svelte-7sr3kz {
    display: inline;
    margin: 0;
    padding: 0;
    border: none;
    background: none;
    font: inherit;
    color: #1d4ed8; /* blue-700 — passes AA on the slate-100 header tint */
    text-decoration: underline;
    text-underline-offset: 2px;
    white-space: nowrap; /* a control may wrap the row, never split in half */
    cursor: pointer;
  }
  .weatherOverlayNoteLink.svelte-7sr3kz:hover {
    color: #1e3a8a; /* blue-900 */
  }
  html.dark .weatherOverlayNoteLink.svelte-7sr3kz {
    color: #93c5fd; /* blue-300 */
  }
  html.dark .weatherOverlayNoteLink.svelte-7sr3kz:hover {
    color: #bfdbfe; /* blue-200 */
  }
  .weatherOverlayNoteDay.svelte-7sr3kz,
  .weatherOverlayNoteDaySep.svelte-7sr3kz {
    white-space: nowrap;
  }
  /* Wide presentation: the connective prose is rendered and the chip label and
     chip separators are not. The narrow block below swaps exactly these two
     sets — one set of CONTROLS serves both, which is the whole point: a second
     copy would double every button for a screen reader and for any query that
     counts them. */
  .weatherOverlayNoteChipLabel.svelte-7sr3kz,
  .weatherOverlayNoteSep.svelte-7sr3kz {
    display: none;
  }
  /* Panel too narrow for title + cadence + note + toggles + ✕ → drop the "updated …"
     note first; it is the only decorative item in the row, and the toggles are
     controls. Threshold measured against the rendered header, not guessed. */
  @container (max-width: 610px) {
    .weatherOverlayUpdated.svelte-7sr3kz {
      display: none;
    }
  }
  /* U28 / R39 — the note row's degrade. Re-COMPOSED, never truncated: the
     prose drops out and the same three controls become a labelled chip row,
     `Affected by: Sailing · Activity · Dates · day 3`. All three targets
     survive at full size and nothing is hidden behind an ellipsis — which is
     what `text-overflow: ellipsis; white-space: nowrap` would have done to
     whichever control fell off the end, and the controls ARE the row.

     Threshold MEASURED, not inherited from any row above. The full sentence
     renders at ~40× the font size of text, against `container − 48px` of usable
     width, and below that it wraps three and four lines deep as the panel
     narrows — exactly the "tripling the panel's height" R39 forbids. It is not
     the 330px breakpoint the header's droppable "within" uses: degrading at 330
     would leave every phone on the multi-line version (an iPhone SE renders this
     panel 343px wide) — correct against the letter of the plan and wrong on the
     device the requirement is about.

     U8 / R6 MOVED this from 470 to 530 and out of the toggles' block. At the
     old 11px the sentence was ~440px wide and held one line down to a ~490px
     panel, so 470 — where the toggles break anyway — was close enough to be
     worth sharing. The row's floor is now 12px (~480px of text, one line down to
     528), so keeping 470 would have opened a 470–528 band showing two-line prose
     where there used to be one line. The toggles keep their own 470 break, which
     was never about this row's text; between 530 and 470 the panel simply gains
     the chip form a little earlier. */
  @container (max-width: 530px) {
    .weatherOverlayNoteProse.svelte-7sr3kz {
      display: none;
    }
    .weatherOverlayNoteChipLabel.svelte-7sr3kz,
    .weatherOverlayNoteSep.svelte-7sr3kz {
      display: inline;
    }
    /* "sailing" → "Sailing": chips are labels, not sentence fragments. Done in
       CSS so the markup carries the prose casing once, and the two
       presentations cannot drift into two copies of the same three words. */
    .weatherOverlayNoteLink.svelte-7sr3kz {
      text-transform: capitalize;
    }
  }
  /* Narrow: the row can no longer hold cadence + toggles. Break it in two, with the
     toggles starting the second row, left-aligned. The ✕ needs no rule here — it is
     pinned to the header corner and out of the flow, so it stays at the first row's
     right end (where it always is, and so never moves under the thumb) on its own.
     The phone layout still gains exactly two rows, both single-line (measured: the
     note row at the 12px floor; panel 111px wide-open, 119px on a phone). */
  @container (max-width: 470px) {
    .weatherOverlayToggles.svelte-7sr3kz {
      margin-left: 0; /* left-align: no auto margin pushing it right */
      flex-basis: 100%;
      padding-top: 4px;
    }
  }
  /* Even narrower (no room for title + cadence + ✕) → drop the word "within"
     ("Peak wind:") so the ✕ still fits on the row. Threshold tuned so iPhone-SE-width
     panels (~343px) keep the full "Peak wind within:".

     "within" is the droppable word rather than "wind": "Peak wind:" still names
     the quantity, where "Peak within:" names nothing at all. */
  @container (max-width: 330px) {
    .weatherOverlayTitleWord.svelte-7sr3kz {
      display: none;
    }
  }
  /* The ✕ is pinned to the header's top-right corner instead of flowing as the
     last flex item.
     As a flex child it wrapped: the row's natural width (title + cadence + note
     + both toggle groups) exceeds the panel at every size between the 470px
     two-row breakpoint and roughly 1060px, so the ✕ — the last and most
     droppable item — spilled onto a second row and, having no auto margin in
     that range, sat at its LEFT edge. Widening the breakpoint ladder would have
     traded one hard-coded guess for another; taking the button out of the flow
     makes "end of the first row" true at every width by construction, and the
     header's reserved right padding keeps wrapped content clear of it. */
  .weatherOverlayClose.svelte-7sr3kz {
    position: absolute;
    top: 6px;
    right: 10px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: #6b7280;
    font-size: 14px;
    line-height: 1;
    cursor: pointer;
  }
  /* Expand the touch target to ~44px without changing the 22px visual or layout
     (the pseudo-element is absolute, so it adds no box) — outdoor mobile use. */
  .weatherOverlayClose.svelte-7sr3kz::after {
    content: '';
    position: absolute;
    inset: -11px;
  }
  .weatherOverlayClose.svelte-7sr3kz:hover {
    background: rgba(0, 0, 0, 0.06);
    color: #111827;
  }
  html.dark .weatherOverlayTitle.svelte-7sr3kz {
    color: #f3f4f6;
  }
  html.dark .weatherOverlayNote.svelte-7sr3kz {
    color: #9ca3af;
  }
  html.dark .weatherOverlayClose.svelte-7sr3kz {
    color: #9ca3af;
  }
  html.dark .weatherOverlayClose.svelte-7sr3kz:hover {
    background: rgba(255, 255, 255, 0.1);
    color: #f3f4f6;
  }

  .mapWrapper.svelte-7sr3kz {
    width: 100%;
    height: 100%;
    position: relative;
    /* Use `clip` (not `hidden`) so the hidden ItineraryPanel — which lives
       off-screen at translateX(panelWidth) and extends the wrapper's
       scrollWidth — cannot be scrolled into view by the browser's
       focus-into-view heuristic. Without this, opening the InfoPanel can
       shift the whole map left by panelWidth, leaving a panel-sized
       whitespace strip on the right of the viewport. */
    overflow: clip;
  }

  .mapContainerStack.svelte-7sr3kz {
    position: absolute;
    inset: 0;
    transition: width 0.3s ease, height 0.3s ease;
  }

  .mapContainer.svelte-7sr3kz {
    width: 100%;
    height: 100%;
    transition: width 0.3s ease, height 0.3s ease; /* Smooth transition */
  }

  .mapContainerLayer.svelte-7sr3kz {
    position: absolute;
    inset: 0;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0s linear;
  }

  .mapContainerLayer.is-active.svelte-7sr3kz {
    opacity: 1;
    pointer-events: auto;
  }

  /* Map sizing is now handled dynamically via inline styles on .mapContainerStack */

  .toggle-map-id {
    position: absolute;
    bottom: 165px;
    right: 10px;
    z-index: 1000;
    padding: 10px;
    background-color: #fff;
    color:rgba(0, 0, 0, 0.7);
    border:0;
    border-radius: 50%;
    cursor: pointer;
    width:40px;
    height:40px;
    display:flex;
    justify-content: center;
    align-items: center;
  }

    .divider {
      border-top: 1px solid #cacaca;
      width: 100%;
    }

  .lat-lng-display-container.svelte-7sr3kz {
    position: absolute;
    bottom: 10px;
    transform: translateX(-50%);
    z-index: 1;
    background-color: rgba(0, 0, 0, 0.7);
    border-radius: 5px;
    padding: 5px 10px;
    display: flex;
    align-items: center;
    font-family: 'Roboto', sans-serif; /* Use a standard font */
    font-size: 0.8em;
    color: #333; /* Darker text for readability */
    transition: bottom 0.3s ease;
  }

  .lat-lng-display.svelte-7sr3kz {
    display: flex;
      align-items: center;
    white-space: nowrap; /* Prevent wrapping */
    border:0px;
    color: white;
    font-family: 'Open Sans', sans-serif;
    font-size: 14px;
    background:transparent;
    display: flex;
    gap: 5px;
  }

  .chatbot-result-marker {
    position: relative;
  }

  .chatbot-result-marker img.advanced-marker-icon {
    width: 40px;
    height: 34px;
  }

  .chatbot-result-number {
    position: absolute;
    top: -5px;
    right: -3px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: #3B82F6;
    color: white;
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
    border: 1.5px solid white;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
  }

  .featured-marker img.advanced-marker-icon {
    filter: drop-shadow(0 0 4px rgba(245, 158, 11, 0.8)) drop-shadow(0 0 8px rgba(245, 158, 11, 0.5));
  }

  .mapWrapper.ai-build-hiding-pois.svelte-7sr3kz .custom-advanced-marker:not([data-ai-build-marker='true']) {
    opacity: 0;
    transform: translateY(20px) scale(0.75);
    transition: opacity 0.24s ease, transform 0.24s ease;
    pointer-events: none;
  }

  .ai-build-icon-marker {
    position: relative;
    transform: translateY(20px) scale(0);
    transform-origin: center bottom;
    animation: svelte-7sr3kz-ai-build-pop-in 0.46s cubic-bezier(0.2, 0.9, 0.24, 1.18) forwards;
    filter: drop-shadow(0 10px 18px rgba(15, 23, 42, 0.24));
    user-select: none;
  }

  .ai-build-icon-marker__icon {
    display: block;
    width: 46px;
    height: 40px;
  }

  .ai-build-icon-marker__fallback {
    width: 46px;
    height: 46px;
    border-radius: 999px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: white;
    color: #0f172a;
    font-family: 'Open Sans', sans-serif;
    font-size: 18px;
    font-weight: 700;
    border: 3px solid rgba(255, 255, 255, 0.96);
    box-shadow: 0 10px 20px rgba(15, 23, 42, 0.22);
  }

  .ai-build-icon-marker::after {
    content: '';
    position: absolute;
    left: 50%;
    top: 38%;
    width: 34px;
    height: 34px;
    border-radius: 999px;
    transform: translate(-50%, -50%);
    background: rgba(59, 130, 246, 0.12);
    box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.18);
    animation: svelte-7sr3kz-ai-build-ring 1.7s ease-out infinite;
    z-index: -1;
  }

  .ai-build-icon-marker--start .ai-build-icon-marker__icon {
    width: 58px;
    height: 50px;
  }

  .ai-build-icon-marker--winner .ai-build-icon-marker__icon {
    width: 54px;
    height: 46px;
  }

  .ai-build-icon-marker--day .ai-build-icon-marker__icon {
    width: 62px;
    height: 54px;
  }

  .ai-build-icon-marker--stop .ai-build-icon-marker__icon {
    width: 38px;
    height: 32px;
  }

  .ai-build-icon-marker--start::after {
    background: rgba(13, 148, 136, 0.14);
    box-shadow: 0 0 0 0 rgba(13, 148, 136, 0.18);
  }

  .ai-build-icon-marker--winner::after,
  .ai-build-icon-marker--day::after {
    background: rgba(37, 99, 235, 0.14);
    box-shadow: 0 0 0 0 rgba(37, 99, 235, 0.18);
  }

  .ai-build-icon-marker__label {
    position: absolute;
    top: -9px;
    right: -8px;
    min-width: 24px;
    height: 24px;
    border-radius: 999px;
    padding: 0 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #0f172a;
    color: white;
    border: 2px solid rgba(255, 255, 255, 0.96);
    box-shadow: 0 8px 16px rgba(15, 23, 42, 0.2);
    font-family: 'Open Sans', sans-serif;
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.03em;
  }

  .ai-build-icon-marker__score {
    position: absolute;
    bottom: -8px;
    left: 50%;
    transform: translateX(-50%);
    min-width: 20px;
    height: 16px;
    border-radius: 8px;
    padding: 0 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #3b82f6;
    color: white;
    border: 1.5px solid rgba(255, 255, 255, 0.96);
    box-shadow: 0 2px 6px rgba(59, 130, 246, 0.3);
    font-family: 'Open Sans', sans-serif;
    font-size: 7.5px;
    font-weight: 700;
    line-height: 1;
  }

  @keyframes svelte-7sr3kz-ai-build-pop-in {
    0% {
      transform: translateY(20px) scale(0);
      opacity: 0;
    }
    65% {
      transform: translateY(20px) scale(1.22);
      opacity: 1;
    }
    100% {
      transform: translateY(20px) scale(1);
      opacity: 1;
    }
  }

  @keyframes svelte-7sr3kz-ai-build-ring {
    0% {
      transform: translate(-50%, -50%) scale(0.78);
      opacity: 0.7;
    }
    75% {
      transform: translate(-50%, -50%) scale(1.9);
      opacity: 0;
    }
    100% {
      transform: translate(-50%, -50%) scale(1.9);
      opacity: 0;
    }
  }


  .map-loading-indicator.svelte-1h9cs4g {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    /* Fits inside the chrome band's 8px of top padding (AppChrome.svelte's
       `--map-chrome-h: 60px` with `padding: 8px 10px`), so it sits above the
       logo pill rather than over any control or any map pixel the chrome was
       not already covering. */
    height: 3px;
    background-color: var(--color-fm-red, #e11d48);
    /* Above the map chrome band (z-mapchrome, 100) and below z-confirm
       (1200), so no dialog, picker or modal is ever crossed by a 3px line. */
    z-index: 1150;
    pointer-events: none;
    opacity: 0;
    /* The ONLY motion in this element, and it is a fade of the indicator
       itself — not of anything laid over the canvas. Mounted permanently at
       opacity 0 so the transition has a baseline from first paint. */
    transition: opacity 0.2s ease-in-out;
  }

  .map-loading-indicator.is-busy.svelte-1h9cs4g {
    opacity: 1;
  }

  @media (prefers-reduced-motion: reduce) {
    .map-loading-indicator.svelte-1h9cs4g {
      transition: none;
    }
  }

