/* Phone layout (js/mobile-layout.js puts html.is-mobile on the page). Loaded after style.css and made of
   nothing but html.is-mobile rules, so the PC layout cannot change: test/mobile-markup.test.js refuses any
   selector here that does not start with it. The one exception keeps phone-only elements off the PC page. */
.mobile-only { display: none; }
html.is-mobile .mobile-only:not(.hidden) { display: block; }

/* ---- Shell (trinn 1; trinn 3 polishes the top bar) ---- */
html.is-mobile {
  --m-top: calc(env(safe-area-inset-top, 0px) + 10px);
  /* The bottom edge of the Beregn bar, kept up to date by mobileTrackBottom; 74px until it is measured. */
  --m-topbar-bottom: 74px;
  /* Room kept clear along the bottom edge for the map's credit line (Leaflet, MapLibre), above the safe area. */
  --m-clear: 24px;
  /* How much of the result sheet shows while it is a strip: its title and the main figure. */
  --m-sheet-peek: calc(116px + env(safe-area-inset-bottom, 0px));
}
html.is-mobile, html.is-mobile body { overflow: hidden; }
/* Fixed, so iOS cannot scroll the page up to show a focused field (the keyboard would otherwise leave the bar half off). */
html.is-mobile body { position: fixed; inset: 0; width: 100%; overscroll-behavior: none; } /* a pull on the map must not pull the page */
html.is-mobile button, html.is-mobile label { touch-action: manipulation; } /* no double-tap zoom on controls */
html.is-mobile #calc-box {
  left: calc(env(safe-area-inset-left, 0px) + 10px); right: calc(env(safe-area-inset-right, 0px) + 10px);
  top: var(--m-top); transform: none; min-width: 0;
  max-width: 560px; margin-inline: auto; /* on a wide screen: a centred bar, not one the whole width of the screen */
  /* One row once a point is chosen: status, date and time, then the two round buttons on the right. The Beregn bar
     (#progress) steps out of the way with display: contents so its buttons become cells of this row. */
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto auto; column-gap: 0; row-gap: 4px; align-items: center;
  padding: 6px 8px;
}
/* The invitation (no point yet): one slim line, the date and time beside it when the shade is on. */
html.is-mobile #calc-hint {
  grid-column: 1 / -1; grid-row: 1; margin: 0; min-height: 36px; white-space: normal; font-size: 13px; padding: 0 12px; line-height: 1.3;
  /* [sun Sol] [text]: left, the text may wrap (the PC rule centres it on one line) */
  display: flex; align-items: center; justify-content: flex-start; gap: 8px; text-align: left;
}
/* The ID rule above beats .hidden, so the invitation must be put away explicitly once a point is chosen. */
html.is-mobile #calc-hint.hidden { display: none; }
/* The mark: the sun of the Beregn button in gold on the light hint, and the name in semibold. Identity, not a button. */
html.is-mobile .calc-hint-brand { flex: none; display: inline-flex; align-items: center; gap: 4px; font-weight: 700; color: var(--ink); }
html.is-mobile .calc-hint-brand::before {
  content: ''; width: 16px; height: 16px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='4.2' fill='%23e5a400'/%3E%3Cpath d='M12 2.5v3M12 18.5v3M2.5 12h3M18.5 12h3M5.3 5.3l2.1 2.1M16.6 16.6l2.1 2.1M18.7 5.3l-2.1 2.1M7.4 16.6l-2.1 2.1' stroke='%23e5a400' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
}
html.is-mobile #calc-hint-text { min-width: 0; font-size: 12px; line-height: 1.25; }
html.is-mobile #calc-box:has(#mobile-date:not(.hidden)) #calc-hint { grid-column: 1; }
/* With a point chosen the hint shares the row with the round buttons, and gives way to the shade line when that has something to say. */
html.is-mobile #calc-box:has(#progress:not(.hidden)) #calc-hint { grid-column: 1; }
html.is-mobile #calc-box:has(#point-shade:not(.hidden)) #calc-hint { display: none; }
html.is-mobile #progress { min-width: 0; flex-wrap: wrap; padding: 6px 8px; }
html.is-mobile #progress.calc-bar--idle:not(.hidden) { display: contents; }
/* While it calculates: the patience bar takes the whole width, the status and date drop to the line under it. */
html.is-mobile #progress:not(.calc-bar--idle) { grid-column: 1 / -1; grid-row: 1; margin: 0; }
html.is-mobile #calc-box:has(#progress:not(.calc-bar--idle):not(.hidden)) #point-shade,
html.is-mobile #calc-box:has(#progress:not(.calc-bar--idle):not(.hidden)) #mobile-date { grid-row: 2; }
html.is-mobile #cancel-fetch-btn { min-height: 44px; min-width: 44px; }
/* Beregn solinnstråling: the one big button became a round icon like all the others. The words stay in the tree as the
   button's name (font-size: 0, never display: none). */
html.is-mobile #calculate-btn {
  grid-column: 3; grid-row: 1; margin-left: 8px;
  flex: none; width: 44px; height: 44px; min-width: 44px; min-height: 44px; padding: 0; border-radius: 50%;
  font-size: 0;
  background: var(--accent-strong) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='4.2' fill='%23fff'/%3E%3Cpath d='M12 2.5v3M12 18.5v3M2.5 12h3M18.5 12h3M5.3 5.3l2.1 2.1M16.6 16.6l2.1 2.1M18.7 5.3l-2.1 2.1M7.4 16.6l-2.1 2.1' stroke='%23fff' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") center / 28px 28px no-repeat;
}
html.is-mobile #calculate-btn:disabled { background-color: #b9c9e3; }
html.is-mobile #clear-point-btn { grid-column: 4; grid-row: 1; margin-left: 8px; width: 44px; height: 44px; padding: 10px; }
/* Status ("I sol", "Skygge fra bygg og trær"): to the left, may break onto two lines. */
html.is-mobile #point-shade { grid-column: 1; grid-row: 1; margin: 0; justify-content: flex-start; flex-wrap: nowrap; font-size: 14px; text-align: left; min-width: 0; }
html.is-mobile #point-shade-text { white-space: normal; line-height: 1.2; min-width: 0; }
/* The date and the time of the sliders, "15. Okt · 14:30", in the same row (the pill beside the sliders was read as
   belonging to the clock). */
html.is-mobile #mobile-date { grid-column: 2; grid-row: 1; margin: 0 0 0 8px; justify-self: end; white-space: nowrap; font-size: 14px; font-weight: 700; text-align: right; color: var(--ink); font-variant-numeric: tabular-nums; }
html.is-mobile #calc-error { grid-column: 1 / -1; margin: 0; }
html.is-mobile #point-sun-msg { grid-column: 1 / -1; margin: 0; }

/* ---- Horizontal sliders (date, clock) ----
   The bars, thumbs, ticks and bubbles are the same on the PC and live in css/style.css (width, centring); the phone only
   lifts the container: it stands on the bottom edge, over the result strip (the lift is capped at the strip's height: an open
   sheet covers the sliders while the answer is read, rather than pushing them up the screen) and over the stack of texts,
   with the map's credit line between. Both are kept by mobileTrackHeight (0 when absent). A bubble reaches 46 px above it. */
html.is-mobile {
  /* Room above the strip for the credit line (Leaflet: 14 px + air); the taller MapLibre line is --m-clear, below. */
  --m-slider-clear: 18px;
}
html.is-mobile:has(body.map3d-open) { --m-slider-clear: var(--m-clear); }
html.is-mobile #mobile-sliders {
  z-index: 11; pointer-events: none; /* a frame for the zones; takes no touches itself */
  /* max(): the strip's own height already holds the safe area, so it is not counted twice; with no strip the safe area stands alone. */
  bottom: calc(max(min(var(--m-sheet-h, 0px), var(--m-sheet-peek)), env(safe-area-inset-bottom, 0px)) + var(--m-bottom-stack, 0px) + var(--m-slider-clear) + 6px);
}

/* In 3D the rotate/tilt/compass buttons stand in the bottom right corner (44 px + 8 px margin = 52 px from the edge), where the
   centred tracks of a narrow screen reach: the right edge is pulled in to --m-ctrl-clear (52 px + air), the left stays at the
   20 px of air. On a screen wide enough for the centred 560 px to clear the buttons, the margins are the centring one, as before. */
html.is-mobile { --m-ctrl-clear: 64px; }
html.is-mobile:has(body.map3d-open) #mobile-sliders {
  width: auto;
  margin-left: max(20px, calc((100% - 560px) / 2));
  margin-right: max(var(--m-ctrl-clear), calc((100% - 560px) / 2));
}

/* The ring and the half-arc are hidden on the PC too now; kept here so the phone never depends on that. */
html.is-mobile .shadow-dial-row, html.is-mobile .shadow-arc-wrap { display: none; }

/* ---- Trinn 2: the panel becomes two columns of round buttons on the edges (like Entur) ----
   The existing buttons are reused as they are (same ids, same handlers in js/app.js, same is-busy / is-far /
   aria-pressed states), so there is no second set to keep in step. #left-column stops being a box, so the
   panel's fixed position is relative to the screen; the panel loses its backdrop-filter, which would otherwise
   become the containing block of anything fixed inside it (the search bar, the messages). */
html.is-mobile #left-column { display: contents; }
html.is-mobile #panel {
  /* Two columns of the same buttons: the left (shade) is grid column 1, the right (map) is column 3, the middle is the map. */
  position: fixed; z-index: 12; left: calc(env(safe-area-inset-left, 0px) + 8px); right: calc(env(safe-area-inset-right, 0px) + 8px);
  /* position: fixed is a stacking context of its own, so the messages and the search bar (inside it) rank by THIS number
     against the sliders (11), the Beregn bar (9) and the map (1, 5 for 3D). Over the sliders, under the sheets (15). */
  top: calc(var(--m-topbar-bottom) + 8px);
  padding: 0; margin: 0;
  display: grid; grid-template-columns: 44px 1fr 44px; grid-auto-rows: 44px; grid-auto-flow: row dense; row-gap: 8px; column-gap: 0;
  max-height: calc(100vh - var(--m-topbar-bottom) - 16px - env(safe-area-inset-bottom, 0px));
  max-height: calc(100dvh - var(--m-topbar-bottom) - 16px - env(safe-area-inset-bottom, 0px));
  background: none; backdrop-filter: none; -webkit-backdrop-filter: none; box-shadow: none; border-radius: 0;
  overflow: visible; scrollbar-gutter: auto; pointer-events: none; /* only the buttons take touches */
}
html.is-mobile #panel button, html.is-mobile #panel label, html.is-mobile #panel input { pointer-events: auto; }
html.is-mobile .panel-header, html.is-mobile .panel-header-actions, html.is-mobile .map-controls-row, html.is-mobile .view-switch-row,
html.is-mobile .shadow-switch-row, html.is-mobile .shadow-level-row, html.is-mobile #shadow-level-picker, html.is-mobile .address-row,
html.is-mobile .address-field-group.is-collapsed { display: contents; }
/* display: contents on the picker would beat its .hidden (an ID rule outranks the class), so it is repeated. */
html.is-mobile #shadow-level-picker.hidden { display: none; }
html.is-mobile .app-title, html.is-mobile .section-label { display: none; }
/* Left: the shade (what changes with the sun). Right: the map and the help. Top to bottom in this order; a hidden one
   leaves no gap (a hidden element takes no grid cell). */
html.is-mobile #lang-btn { grid-column: 1; order: 0; }
html.is-mobile #shadow-btn { grid-column: 1; order: 1; }
html.is-mobile #shadow-refresh-btn { grid-column: 1; order: 2; }
html.is-mobile #shadow-level-btn { grid-column: 1; order: 3; }
html.is-mobile .map3d-ground-row { grid-column: 1; order: 4; }
html.is-mobile #building-add-btn { grid-column: 1; order: 5; }
html.is-mobile #address-open-btn { grid-column: 3; order: 6; }
html.is-mobile #geolocate-btn { grid-column: 3; order: 7; }
html.is-mobile #view-toggle-btn { grid-column: 3; order: 8; }
html.is-mobile .layer-toggle { grid-column: 3; order: 9; }
html.is-mobile #info-btn { grid-column: 3; order: 10; }
html.is-mobile #method-btn { grid-column: 3; order: 11; }
/* The compass sat bottom left, where the sliders and the left column now are; the 2D map is north up anyway. */
html.is-mobile #map-compass { display: none; }

/* ---- Trinn 2: the buttons become round icons ---- */
/* Every button: one round 44 px target (WCAG 2.5.5 / Apple HIG), whatever size the PC gave it. flex: none, because
   the PC pills have flex: 1 and would stretch upright in a column. */
html.is-mobile #address-open-btn, html.is-mobile #geolocate-btn, html.is-mobile #view-toggle-btn, html.is-mobile .layer-toggle,
html.is-mobile #shadow-btn, html.is-mobile #shadow-refresh-btn, html.is-mobile #shadow-level-btn, html.is-mobile .map3d-ground-row,
html.is-mobile #building-add-btn, html.is-mobile #info-btn, html.is-mobile #method-btn, html.is-mobile #lang-btn {
  position: relative; flex: none; box-sizing: border-box; width: 44px; height: 44px; margin: 0; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%; background: rgba(255, 255, 255, 0.95); color: var(--ink);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25); cursor: pointer; font: inherit; font-size: 12px; font-weight: 700; line-height: 1;
}
html.is-mobile #address-open-btn svg, html.is-mobile #geolocate-btn svg, html.is-mobile #building-add-btn svg { width: 24px; height: 24px; }
html.is-mobile #address-open-btn, html.is-mobile #geolocate-btn { padding: 0; }
html.is-mobile #shadow-refresh-btn { font-size: 22px; }
html.is-mobile #shadow-refresh-btn:disabled { animation: shadow-refresh-spin 0.8s linear infinite; opacity: 1; } /* the existing keyframes */
html.is-mobile #shadow-refresh-btn.is-far, html.is-mobile #building-add-btn.is-far { opacity: 0.45; }
html.is-mobile #building-add-btn:disabled { opacity: 0.45; }
/* An ID or two-class rule above would outrank the PC's .hidden, so it is said again here. */
html.is-mobile #shadow-refresh-btn.hidden, html.is-mobile .map3d-ground-row.hidden { display: none; }

/* 2D/3D and Nabolag/Område: the name of where a press goes, inside the circle. */
html.is-mobile #view-toggle-btn { font-size: 14px; }
html.is-mobile #shadow-level-btn { font-size: 10px; letter-spacing: -0.2px; }

/* Topokart: the map crop IS the button; the word stays for screen readers. */
html.is-mobile .layer-toggle { padding: 4px; }
html.is-mobile .layer-toggle img { width: 100%; height: 100%; border-radius: 50%; }
html.is-mobile .layer-toggle span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; }
html.is-mobile .layer-toggle:has(input:checked) { box-shadow: 0 0 0 3px var(--accent), 0 2px 8px rgba(0, 0, 0, 0.25); background: #e8f0fe; }
html.is-mobile .layer-toggle:has(input:focus-visible) { outline: 2px solid var(--focus); outline-offset: 4px; }

/* Skyggekart: an icon (sun behind a building that throws a shadow), the dot/spinner as a badge. The text, which is
   the live state, stays in the tree. */
html.is-mobile #shadow-btn {
  font-size: 0; /* hides the text, keeps it as the accessible name */
  background: rgba(255, 255, 255, 0.95) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='8' cy='8' r='3.2' fill='%23e5a400'/%3E%3Cpath d='M8 1.5v2M1.5 8h2M3.4 3.4l1.4 1.4M12.6 3.4l-1.4 1.4' stroke='%23e5a400' stroke-width='1.6' stroke-linecap='round'/%3E%3Cpath d='M9 22V11h7v11z' fill='%235f6368'/%3E%3Cpath d='M16 22l5-4v4z' fill='%23000' fill-opacity='.35'/%3E%3C/svg%3E") center / 28px 28px no-repeat;
}
html.is-mobile #shadow-btn::before { position: absolute; top: 4px; right: 4px; width: 10px; height: 10px; margin: 0; box-sizing: border-box; }
html.is-mobile #shadow-btn[aria-pressed="true"] { box-shadow: 0 0 0 3px #2e9d4f, 0 2px 8px rgba(0, 0, 0, 0.25); background-color: #e3f3e8; color: #1b6b35; }
html.is-mobile #shadow-btn.is-far { opacity: 0.55; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); }

/* Skygge på bakken: the same recipe; the checkbox itself is invisible on top, the label is the button. */
html.is-mobile .map3d-ground-row input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
html.is-mobile .icon-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; }
html.is-mobile .map3d-ground-row {
  background: rgba(255, 255, 255, 0.95) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='3' y='3' width='18' height='18' rx='2' fill='%23c8d3e0'/%3E%3Cpath d='M3 21L21 3v18z' fill='%23000' fill-opacity='.35'/%3E%3C/svg%3E") center / 26px 26px no-repeat;
}
html.is-mobile .map3d-ground-row:has(input:checked) { box-shadow: 0 0 0 3px var(--accent), 0 2px 8px rgba(0, 0, 0, 0.25); }
html.is-mobile .map3d-ground-row:has(input:focus-visible) { outline: 2px solid var(--focus); outline-offset: 4px; }

/* Info: «?» in the circle, the words stay in the tree. */
html.is-mobile #info-btn { font-size: 0; }
html.is-mobile #info-btn::after { content: "?"; font-size: 20px; font-weight: 700; }
html.is-mobile #info-btn[aria-expanded="true"], html.is-mobile #method-btn[aria-expanded="true"] { background: var(--accent); color: #fff; }
html.is-mobile #method-btn { font-size: 20px; font-style: italic; }

/* ---- Messages: one line under the top bar, in the colours they already have ----
   showMsg/hideMsg in js/app.js are unchanged; a tap hides the message (mobileDismissOnTap). They stop short of the
   icon columns (44 + 2 x 8 px each side). */
html.is-mobile #shadow-msg, html.is-mobile #shadow-level-msg, html.is-mobile #view-msg, html.is-mobile #address-msg {
  position: fixed; z-index: 13; left: 64px; right: 64px; margin: 0 auto; max-width: 560px;
  top: calc(var(--m-topbar-bottom) + 8px);
  padding: 10px 12px; border-radius: 10px; font-size: 13px; line-height: 1.35;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25); pointer-events: auto;
}
html.is-mobile #shadow-msg.hidden, html.is-mobile #shadow-level-msg.hidden, html.is-mobile #view-msg.hidden, html.is-mobile #address-msg.hidden { display: none; }

/* ---- Search: opened, it is one line over the top bar (the field is 16 px so iOS does not zoom in), the list under it ---- */
html.is-mobile .address-field-group:not(.is-collapsed) {
  position: fixed; z-index: 14; top: var(--m-top); left: 10px; right: 10px; margin: 0 auto; max-width: 560px; padding: 8px;
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  background: #fff; border-radius: 12px; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.25); pointer-events: auto;
}
html.is-mobile body:has(.address-field-group:not(.is-collapsed)) #calc-box { visibility: hidden; }
/* The label is for screen readers (the placeholder shows what to type); the row is display: contents, so the field
   and the position button are siblings in the flex line. */
html.is-mobile .address-field-group:not(.is-collapsed) .address-label {
  position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap;
}
html.is-mobile #address-input { flex: 1 1 0; min-width: 0; width: auto; height: 44px; box-sizing: border-box; padding: 0 12px; font-size: 16px; border-radius: 22px; }
/* Cancel: a quiet round button at the end of the search line, only while the search is open. */
html.is-mobile #address-cancel-btn {
  flex: none; box-sizing: border-box; width: 44px; height: 44px; margin: 0; padding: 0; border: 0; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; background: #f1f3f6; box-shadow: none; cursor: pointer;
}
html.is-mobile #address-cancel-btn svg { width: 22px; height: 22px; }
html.is-mobile .address-field-group.is-collapsed #address-cancel-btn { display: none; }
html.is-mobile #address-suggestions {
  position: static; flex-basis: 100%; order: 20; margin: 0;
  max-height: 40vh; max-height: min(40dvh, calc(var(--m-vv-height, 100dvh) - var(--m-top) - 76px)); overflow-y: auto;
}

/* ---- Info and Metode: a sheet the width of the screen under the top bar ---- */
html.is-mobile #underlay-panel { z-index: 14; }
html.is-mobile #info-panel, html.is-mobile #method-panel {
  z-index: 15; left: 10px; right: 10px; width: auto; max-width: 640px; margin-inline: auto; top: calc(var(--m-topbar-bottom) + 8px);
  max-height: calc(100vh - var(--m-topbar-bottom) - 24px); max-height: calc(100dvh - var(--m-topbar-bottom) - 24px);
}

/* ---- The stack at the bottom: building pills and the point's texts, under the sliders, between the two columns ---- */
html.is-mobile .panel-bottom {
  position: fixed; z-index: 10; left: 64px; right: 64px; margin: 0 auto; max-width: 560px; /* centred on a wide screen */
  /* The same foot as the sliders' (they stand on top of it): over the strip's height, or the safe area with no strip, and the credit's room. */
  bottom: calc(max(min(var(--m-sheet-h, 0px), var(--m-sheet-peek)), env(safe-area-inset-bottom, 0px)) + var(--m-slider-clear));
  display: flex; flex-direction: column-reverse; gap: 6px; pointer-events: none; /* only what stands in it takes touches */
}
html.is-mobile #shadow-panel { margin: 0; }
html.is-mobile #shadow-window {
  margin: 0 0 6px; padding: 6px 10px; border-radius: 10px; background: rgba(255, 255, 255, 0.95);
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2); font-size: 12px; line-height: 1.35;
}
html.is-mobile .building-list { margin: 0; padding: 6px; border-radius: 10px; background: rgba(255, 255, 255, 0.95); box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2); pointer-events: auto; }

/* ---- The result as a sheet from the bottom edge (the answer lives at the bottom) ----
   A strip by default: the title and the main figure. A tap on the title opens it (js/mobile-layout.js mobileSheetToggle).
   The rest is visibility: hidden, not display: none, because the sun dome measures its width when it is drawn. Open, it is
   at most 55 % tall and never so tall that it covers the lowest buttons of the two columns (they end at y = 376). */
html.is-mobile #result-panel {
  position: fixed; z-index: 11; top: auto; left: 0; right: 0; bottom: 0; width: auto; margin: 0 auto; max-width: 640px;
  max-height: var(--m-sheet-peek); overflow: hidden;
  padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
  border-radius: 16px 16px 0 0; box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.2);
}
html.is-mobile #result-panel.is-open {
  max-height: 55vh; max-height: min(55dvh, calc(100dvh - 392px)); overflow-y: auto;
}
/* The result's columns are invisible to the layout here (a wide screen makes them a grid, at the end of this file). In the strip
   only the main figure shows: the rest of the main column, and the other two columns, are hidden (visibility is inherited
   through display: contents). */
html.is-mobile .result-col { display: contents; }
html.is-mobile #result-panel:not(.is-open) #result-content > .result-col--main > :not(:first-child) { visibility: hidden; }
html.is-mobile #result-panel:not(.is-open) #result-content > .result-col:not(.result-col--main) { visibility: hidden; }
html.is-mobile #result-panel .result-panel-head { min-height: 44px; align-items: center; cursor: pointer; margin-bottom: 0; }
html.is-mobile #result-panel .result-panel-head::after { content: "\25B4"; font-size: 16px; color: var(--muted); }
html.is-mobile #result-panel.is-open .result-panel-head::after { content: "\25BE"; }
/* The stack's texts are for the map; while the answer is being read they step aside. */
html.is-mobile:has(#result-panel.is-open) .panel-bottom { display: none; }

/* ---- Touch targets and field sizes in the rest of the app ---- */
html.is-mobile .close-btn { top: 0; right: 0; width: 44px; height: 44px; font-size: 24px; }
html.is-mobile #info-panel h3, html.is-mobile #method-panel h3, html.is-mobile #underlay-panel h3 { padding-right: 52px; }
html.is-mobile .address-suggestion { min-height: 44px; display: flex; align-items: center; font-size: 14px; }
html.is-mobile .address-suggestion-empty { min-height: 44px; display: flex; align-items: center; }
html.is-mobile .uncertain-btn { width: 44px; height: 44px; font-size: 18px; margin-left: 4px; }
/* The mark is centred on its row, which lands it on the middle of the digits only while the digits are the
   tallest thing there. At 28 px the 44 px touch target is taller than they are and would take over the
   row's height, leaving the mark about 6 px low; pulling the button's own box back to the number's size
   keeps the row the digits' height at every size, so one rule covers both the strip and the wide panel
   (Ricky, 2026-10-13: "den varslingen kan flyttes litt opp"). */
html.is-mobile .uncertain-btn { margin-block: calc((var(--num-size, 28px) - 44px) / 2); }
/* The button into Underlag carries its own 44 px in css/style.css now that it is a button of its own
   rather than the whole "Beregnet med" box (Ricky, 2026-10-13). */
/* The building pills stay small to the eye; the touch area grows round each small button by an invisible layer
   (the same trick style.css uses, with insets big enough for 44 px). */
html.is-mobile .building-row-height { width: 52px; font-size: 16px; padding: 4px 6px; }
html.is-mobile .building-row-calc::after, html.is-mobile .building-row-delete::after,
html.is-mobile .building-row-swatch::after, html.is-mobile .building-row-on::after { content: ''; position: absolute; inset: -13px; }
html.is-mobile .building-row-swatch, html.is-mobile .building-row-on { position: relative; }
html.is-mobile .building-row { gap: 6px; }
/* Underlag: one sheet under the top bar, like Info and Metode. */
html.is-mobile #underlay-panel {
  left: 10px; right: 10px; width: auto; max-width: 640px; margin-inline: auto; transform: none; top: calc(var(--m-topbar-bottom) + 8px);
  max-height: calc(100vh - var(--m-topbar-bottom) - 24px); max-height: calc(100dvh - var(--m-topbar-bottom) - 24px);
}

/* ---- The map's own controls ----
   No zoom buttons: two fingers (or a double tap) zoom on a touch screen, and the buttons only crowded the corner. The
   compass and the rotate/tilt buttons stay (the only way back to north and flat with one finger), 44 px. The credit
   lines are a licence requirement and stay; they and the controls sit above the result sheet, not under it. */
html.is-mobile .leaflet-control-zoom { display: none; }
html.is-mobile .leaflet-bottom { bottom: min(var(--m-sheet-h, 0px), var(--m-sheet-peek)); }
html.is-mobile .leaflet-control-attribution { font-size: 10px; }
html.is-mobile #map3d .maplibregl-ctrl-zoom-in, html.is-mobile #map3d .maplibregl-ctrl-zoom-out { display: none; }
html.is-mobile #map3d .maplibregl-ctrl-group button { width: 44px; height: 44px; }
/* Lifted by the strip only: an open sheet is 350-450 px tall and covers them while the answer is read, rather than
   pushing them up over the right-hand column. */
html.is-mobile #map3d .maplibregl-ctrl-bottom-right, html.is-mobile #map3d .maplibregl-ctrl-bottom-left { bottom: min(var(--m-sheet-h, 0px), var(--m-sheet-peek)); }
html.is-mobile #map3d .maplibregl-ctrl-bottom-right .maplibregl-ctrl { margin: 0 8px 6px 0; }
html.is-mobile #map3d .maplibregl-ctrl-attrib-inner { font: 10px/14px -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
/* MapLibre's credit line is taller than Leaflet's. */
html.is-mobile:has(body.map3d-open) { --m-clear: 56px; }

/* ---- A mouse (Ricky, 2026-10-12: one UI for phone and desktop) ----
   Hover only where there is one (never on a touch screen, where it would stay stuck after a tap); a filter so the
   rule never fights the state rings (pressed, active) that set the shadow and the background. */
@media (hover: hover) {
  html.is-mobile #address-open-btn:hover, html.is-mobile #geolocate-btn:hover, html.is-mobile #view-toggle-btn:hover,
  html.is-mobile .layer-toggle:hover, html.is-mobile #shadow-btn:hover, html.is-mobile #shadow-refresh-btn:hover,
  html.is-mobile #shadow-level-btn:hover, html.is-mobile .map3d-ground-row:hover, html.is-mobile #building-add-btn:hover,
  html.is-mobile #info-btn:hover, html.is-mobile #method-btn:hover, html.is-mobile #clear-point-btn:hover { filter: brightness(0.93); }
  html.is-mobile #calculate-btn:hover:not(:disabled) { filter: brightness(0.88); }
}

/* ---- A wide, tall screen: the result panel stands on the bottom edge (see the end of this file), so the sliders stand on top of
   it, whatever its height: the full sheet, not the strip's cap (an open panel is up to 45 % of the screen and the sliders ride
   above it, so the date and the clock can be moved while the answer is read). The panel's own height -- --m-sheet-h -- is the
   whole measure here: it used to be raised by --m-clear, the air the panel floated on, and that air is gone.
   What stands over the panel is the credit line (the end of this block), so these two clear the LINE, not the panel: the 4 px of
   air under it, the line itself (Leaflet 14 px, MapLibre 24) and 4 px over it. A clock track that reached into the line hid half
   the licence text in 3D at 1200x800 -- measured, not guessed. This is NOT the phone's --m-slider-clear (18 px): that number
   measures the strip's foot, where the credit line stands on something other than the thing above it. ---- */
@media (min-width: 900px) and (min-height: 700px) {
  html.is-mobile { --m-credit-lift: 4px; --m-credit-room: 22px; --m-sheet-side: 80px; }
  html.is-mobile:has(body.map3d-open) { --m-credit-room: 38px; }
  html.is-mobile .panel-bottom { bottom: calc(var(--m-sheet-h, 0px) + env(safe-area-inset-bottom, 0px) + var(--m-credit-room)); }
  html.is-mobile #mobile-sliders {
    bottom: calc(var(--m-sheet-h, 0px) + var(--m-bottom-stack, 0px) + env(safe-area-inset-bottom, 0px) + var(--m-credit-room) + 8px);
  }
}
/* The result sheet is at most 640 px and centred, so it only gets in over the credit lines while the screen is narrower than
   the sheet plus both credit widths: Leaflet's (about 238 px at 10 px type) below 1140 px, MapLibre's open line (about 480 px,
   and it stacks the rotate/tilt buttons with it) below 1600 px. Wider than that they sit in the corner, as on a desktop map. */
@media (min-width: 700px) and (min-height: 600px) and (max-width: 1139px) {
  /* Narrower than the sheet plus the credit, yet wide enough that the sheet is not the whole width: the credit rides above the
     OPEN sheet too (the right-hand column ends at y = 376 and the sheet never starts above 392, so there is room). On a phone
     the open sheet still covers it, as before. */
  html.is-mobile .leaflet-bottom { bottom: var(--m-sheet-h, 0px); }
}
@media (min-width: 1140px) {
  html.is-mobile .leaflet-bottom { bottom: 0; }
}
@media (min-width: 1600px) {
  html.is-mobile #map3d .maplibregl-ctrl-bottom-right, html.is-mobile #map3d .maplibregl-ctrl-bottom-left { bottom: 0; }
}

/* ---- The sun dome in the result must not trap the gestures that scroll the result (js/dome.js setupDomeGestures) ---- */
html.is-mobile #sun-dome-container canvas { touch-action: pan-y; }

/* ---- A big screen (as wide as 900 and as tall as 700, the same cut as the sliders above: a phone on its side, 932 x 430, is
   not one): the result is a wide panel along the bottom, between the two button columns ----
   The same margin on each side -- --m-sheet-side -- so the panel is centred in the window, over the sliders and the stack
   below it, which are centred too. It used to start at x = 270 and end 80 px from the right edge, so its centre sat 95 px
   right of the window's at every width from 900 up (measured in Chrome at 900, 912, 1200, 1440, 1692 and 1920; Ricky saw it
   when he dragged the window wider, 2026-10-16). The 270 protected nothing: both button columns are 44 x 44 px, 8 px in
   from their edge, and sit in the TOP half of the window (y 66..370), while the band x = 80..270 below the panel's top
   edge was empty in every combination measured -- 900x700, 1200x700, 1200x800, 1200x900 and 1920x900, strip and open, 2D
   and 3D. 80 px rather than 52 (= 8 + 44) leaves 28 px of air to the columns, the same air the right side always had;
   below 900 the phone rule centres the sheet itself (left/right 0, margin 0 auto, max-width 640), which is why 854 px
   looked right and 912 did not.
   The panel stands ON the bottom edge -- only the safe area is left under it -- and its lower corners are square, so it
   reads as a sheet pulled up from the edge rather than a card floating over the map (Ricky, 2026-10-16: the phone strip
   already sits like that). Nothing is left at the bottom for the map's credit line, so it and MapLibre's bottom controls
   are lifted by the panel's own height at the end of this block. */
@media (min-width: 900px) and (min-height: 700px) {
  html.is-mobile #result-panel {
    left: calc(env(safe-area-inset-left, 0px) + var(--m-sheet-side)); right: calc(env(safe-area-inset-right, 0px) + var(--m-sheet-side));
    bottom: env(safe-area-inset-bottom, 0px);
    width: auto; max-width: none; margin: 0;
    padding-bottom: 12px; border-radius: 16px 16px 0 0;
    scrollbar-gutter: stable; /* the scrollbar of an open panel must not take width from the sun dome after it was drawn */
  }
  /* A real point holds more than the 45 % cap does: two shade lines, the "Beregnet med" box, the drawn-buildings lines and
     the legend. The rest used to be cut off with no way to reach it (Ricky, 2026-10-13: "Vi må nok kunne scrolle nedover i
     rapporten"). The panel scrolls as one, columns and all, and the head rides along and stops at the top so x is always on
     screen.
     Open, the panel hands its own top padding to the head: a stuck element pins to the padding edge, not the panel's top
     edge, so the strip above it would stay bare and let the figure show through as it scrolled past (seen at 1182x814).
     With the padding on the head itself the two line up in both states -- closed, the panel's 16 px, open, the head's. */
  html.is-mobile #result-panel.is-open {
    max-height: 45vh; max-height: 45dvh; overscroll-behavior: contain; padding-top: 0;
  }
  html.is-mobile #result-panel.is-open .result-panel-head {
    position: sticky; top: 0; z-index: 2;
    background: rgba(255, 255, 255, 0.95);
    padding-top: 16px;
  }
  /* Two rows: the figure and its lines beside the dome, and the month chart across the full width underneath. Three
     columns only from 1920 px.
     Nothing is clipped at 1914 -- measured there and at 2560 px on 2026-10-13, every line (the sources under the dome,
     the chart's caption, the figure's own lines) is already on one line at both, so no width above 1914 buys fit. What
     three columns cost at 1914 is breathing room: they sit edge to edge and feel cramped (Ricky: "Tre kolonner side om
     side føles stramt der, selv om ingenting klippes"). Hence two rows below 1920 -- the round number just above his
     1914 px laptop, so the widths that were working keep their three.
     The wrappers are display: contents on a phone (the rules further up), so the markup is the same and the sheet looks
     exactly as it did. minmax(0, 1fr) rather than 1fr: a grid track will not shrink below its content without it, and the
     dome would push the panel wider than 45vh. The column gap is what the columns get instead of touching; the row gap
     separates the chart from the row above it. */
  html.is-mobile #result-content {
    display: grid; align-items: start;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas: "main dome" "bars bars";
    column-gap: 24px; row-gap: 16px;
  }
  /* grid (1,1,1) outranks ".hidden { display: none }" (0,1,0), so js/app.js's .hidden on
     #result-content -- put there by placePoint, clearPoint and recalculate while a new calculation
     runs -- did nothing above 900x700: the old result stayed on screen, and only a phone put it
     away. Said again here, as #calc-hint, #progress and the shadow panel's messages are. */
  html.is-mobile #result-content.hidden { display: none; }
  html.is-mobile .result-col { display: block; min-width: 0; }
  /* The three parts of the report are three quiet cards: a faint tint, soft corners and some air, so the eye sees where one ends and the next begins. Open only: in the strip the main column's padding would push the figure down and cut it off. */
  html.is-mobile #result-panel.is-open .result-col { padding: 14px 16px; border-radius: 12px; background: #f5f7fa; align-self: stretch; }
  /* Named areas rather than source order: the markup is the same three wrappers in every mode, and on a phone they are
     display: contents, where a grid-area on them means nothing. */
  html.is-mobile .result-col--main { grid-area: main; }
  html.is-mobile .result-col--bars { grid-area: bars; }
  html.is-mobile .result-col--dome { grid-area: dome; }
  /* On a wide screen the answer is said with two figures instead of one small line: the rating number,
     and the year's yield under the stars. The phone keeps the 28 px number and the 12 px line it has
     always had (css/style.css), so none of this reaches the sheet.
     44 px is measured rather than picked: at 1440 and at 1914 the number and its unit still sit on one
     line beside the warning symbol, and the column underneath is where it was -- a size that wrapped the
     unit onto a second line would move everything below it down for nothing. */
  html.is-mobile .result-headline { --num-size: 44px; }
  html.is-mobile .result-value { font-size: var(--num-size); }
  html.is-mobile .result-unit { font-size: 15px; }
  html.is-mobile .result-total { margin-top: 8px; }
  html.is-mobile .result-total-value { font-size: 22px; font-weight: 700; color: var(--ink); }
  html.is-mobile .result-total-area { font-size: 13px; }
  /* The dome shares the top row with the figure. A box that filled its column flattened the drawing instead -- 754 x 317
     at 1914 x 940, three times as wide as tall -- so it keeps the 3:2 it has in the three-column layout and stops at
     380 x 253, where 253 is what the figure beside it stands at that window (measured, not guessed). Narrower than 380
     the box follows its column and the figure still sets the row; wider, the dome stops growing. The row is the figure's
     either way, so the chart below is not pushed out of reach for the sake of a drawing (Ricky, 2026-10-13:
     "Kuppelhøyden skal ikke gjøre øvre rad høyere enn nødvendig"). Left-aligned, so its edge lines up with the sources
     line under it. */
  html.is-mobile .sun-dome-box {
    width: min(100%, 380px);
    aspect-ratio: 3 / 2;
    height: auto;
  }
  /* Three columns again: the dome is alone in its column, so the sum that sizes it is the one measured for that layout --
     the head (44), the gap after it (16), the panel's bottom padding (12) and the sources line's margin (10) and the line
     itself when it wraps to two lines (24) = 106. Measured: at 900-1139 px the dome's column is about 175 px wide and the
     sources take two lines; wider, one. Must come after the two-row rules above, which would otherwise win on every
     width. */
  @media (min-width: 1920px) {
    html.is-mobile #result-content {
      grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr) minmax(0, 1fr);
      grid-template-areas: "main bars dome";
    }
    html.is-mobile .sun-dome-box {
      height: clamp(160px, calc(45vh - 106px), 390px); height: clamp(160px, calc(45dvh - 106px), 390px);
      width: min(100%, calc(clamp(160px, calc(45vh - 106px), 390px) * 1.5));
      aspect-ratio: auto;
    }
  }
  /* Open, the handle stays ▾ (it only folds the report down to the strip) but gets a box big enough for a mouse. It was ✕ here,
     which read as «fjern rapporten» next to the top bar's ✕ that clears the point (Ricky 2026-10-15). */
  html.is-mobile #result-panel.is-open .result-panel-head::after {
    content: "\25BE"; display: flex; align-items: center; justify-content: center;
    width: 44px; height: 44px; font-size: 24px;
  }
  /* The panel stands on the bottom edge, so the corner the credit line used to sit in is inside it. Both credit lines ride
     on the panel's top edge instead -- the panel's own height (--m-sheet-h) plus the safe area is exactly where that edge is
     -- so the licence line meets the panel without ever being covered, folded or open, 2D or 3D. --m-credit-lift is the 4 px
     of air asked for, measured on each library's own bottom container rather than guessed: Leaflet's line ends exactly at its
     container's edge, MapLibre's sits 6 px inside its own (higher up), so the one 4 px number gives 4 px in 2D and 10 in 3D
     (Chrome, 1440x900 and 1200x800). On a phone the strip's height is all that is used (the rules further up), and an open
     sheet there still covers the line, as it always has. */
  html.is-mobile .leaflet-bottom { bottom: calc(var(--m-sheet-h, 0px) + env(safe-area-inset-bottom, 0px) + var(--m-credit-lift, 4px)); }
  html.is-mobile #map3d .maplibregl-ctrl-bottom-right, html.is-mobile #map3d .maplibregl-ctrl-bottom-left { bottom: calc(var(--m-sheet-h, 0px) + env(safe-area-inset-bottom, 0px) + var(--m-credit-lift, 4px)); }
}

/* The little map under the left column's buttons: Scandinavia with the relief lit from where the sun is, three rows tall, a picture only
   (it takes no touches). */
html.is-mobile #mini-map {
  position: relative; grid-column: 1; grid-row: span 3; order: 20; width: 132px; height: 132px; box-sizing: border-box; overflow: hidden;
  border-radius: 14px; background: #bfc8cf; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35); pointer-events: none;
}
html.is-mobile #mini-map.hidden { display: none; }
html.is-mobile #mini-map canvas { filter: contrast(1.6) saturate(1.15) brightness(0.96); } /* the pale map style is too flat to read the relief in a box this small */
html.is-mobile #mini-map::after { /* the place: the map is always centred on it */
  content: ''; position: absolute; left: 50%; top: 50%; width: 5px; height: 5px; margin: -2.5px 0 0 -2.5px; border-radius: 50%;
  background: rgba(230, 81, 0, 0.9); box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.85); z-index: 3;
}
html.is-mobile .mini-map-night { position: absolute; inset: 0; background: #0a1230; opacity: 0; pointer-events: none; z-index: 2; transition: opacity 0.3s; }
html.is-mobile .mini-map-sun {
  position: absolute; width: 46px; height: 46px; margin: -23px 0 0 -23px; border-radius: 50%; opacity: 0; pointer-events: none; z-index: 4;
  background: radial-gradient(circle, rgba(255, 240, 120, 1) 0%, rgba(255, 200, 60, 0.7) 30%, rgba(255, 160, 0, 0) 70%);
}

/* In 3D on a low window with the report open, the corner buttons would lie over the column down the right edge: they stand left of it instead. */
html.is-mobile.map3d-ctrl-aside #map3d .maplibregl-ctrl-bottom-right { right: 60px; }
