/* AuralFM on the web: what a browser tab and an iPhone need that a Mac window
   does not. Loaded after the page's own stylesheet, so it only overrides. */

/* ── what this version does not have yet ─────────────────────────────────────
   Hidden rather than removed, because the page's scripts still wire them up. */
/* Sharing a card needs the clipboard and file writing the desktop app does in
   its main process. */
#nowShare { display: none !important; }
/* Adding your own stations writes a file on the desktop; not here yet. */
.addst { display: none !important; }
/* The Stations / Shortwave tabs hold their space even when empty on the
   desktop; with no shortwave here they would only ever be empty space. */
#railtabs { display: none !important; }

/* ── a tab, not a Mac window ──────────────────────────────────────────────── */
/* No traffic lights to clear, and no window to drag. */
.toolbar { padding-left: 14px; -webkit-app-region: none; }

/* The logo, where the Mac's traffic lights would be. Bone on dark, onyx on
   light — the two colours it is drawn in — whichever way the theme was set. */
.brand { flex: none; display: flex; align-items: center; color: #F7F4EE; }
.brand svg { display: block; height: 18px; width: auto; margin-right: 6px; }
@media (prefers-color-scheme: light) { :root:not([data-theme="dark"]) .brand { color: #0C0B0B; } }
:root[data-theme="light"] .brand { color: #0C0B0B; }
html, body { overscroll-behavior: none; }
/* iOS paints its own grey rectangle over a tap, on top of the app's own press
   state — two answers to one press. */
html { -webkit-tap-highlight-color: transparent; }
/* A tap is a tap: no double-tap-zoom wait on anything in the app. */
button, [role="button"], a, input, select { touch-action: manipulation; }

/* The sheet's handle exists only where the sheet does. In a wide window the
   rail does not move, and an unstyled button above the place name is all that
   is left of it — the strip sitting over "Chicago IL". */
.sheetgrab { display: none; }
/* Headlines' and Chat's handle, made in web/phone-bar.js; phones only. */
.panelgrab { display: none; }

/* ── the Settings sheet (web/sheet.js) ─────────────────────────────────────── */
.setsheet { position: fixed; inset: 0; z-index: 9800; }
.setsheet[hidden] { display: none !important; }
.setsheet-scrim {
  position: absolute; inset: 0; background: rgba(0, 0, 0, .46);
  opacity: 0; transition: opacity var(--dur-panel) var(--ease-out);
}
.setsheet.open .setsheet-scrim { opacity: 1; }
.setsheet-panel {
  position: absolute; left: 50%; top: 50%; translate: -50% -50%;
  width: min(560px, calc(100vw - 48px)); height: min(740px, calc(100dvh - 96px));
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--bg); border-radius: var(--r-xl);
  box-shadow: inset 0 1px 0 var(--edge-hi), 0 0 0 .5px var(--edge-lo), 0 30px 80px rgba(0, 0, 0, .5);
  opacity: 0; transform: scale(.96);
  transition: opacity var(--dur-panel) var(--ease-out), transform .32s var(--ease-drawer);
}
.setsheet.open .setsheet-panel { opacity: 1; transform: none; }
.setsheet-grab {
  display: none; flex: none; width: 36px; height: 5px; margin: 6px auto 0;
  border-radius: var(--r-pill); background: var(--label3);
}
.setsheet-head {
  flex: none; display: flex; align-items: center; justify-content: space-between;
  padding: 8px 8px 6px 20px; box-shadow: inset 0 -.5px 0 var(--line);
}
.setsheet-head h2 { margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -.02em; }
/* Focused only so the dialog has somewhere to start; it is not a control. */
.setsheet-head h2:focus { outline: none; }
.setsheet-done {
  appearance: none; border: 0; background: none; cursor: default;
  min-width: 44px; min-height: 44px; padding: 0 12px; border-radius: var(--r-md);
  color: var(--accent); font: inherit; font-size: 17px; font-weight: 600;
}
.setsheet-done:hover { background: var(--fill); }
.setsheet-done:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.setsheet-frame { flex: 1; width: 100%; border: 0; background: var(--bg); color-scheme: normal; }

/* Reduced motion: a cross-fade, and nothing moves. */
.setsheet.fade .setsheet-panel { transform: none !important; transition: opacity 200ms ease; }

/* ── Add to Home Screen (web/install.js) ──────────────────────────────────────
   A card at the bottom, where Safari's own controls are, over everything the
   app draws. One step lit at a time, its glyph above with a tap drawn on it. */
.installhint {
  position: fixed; z-index: 9900; left: 50%; translate: -50% 0;
  bottom: calc(12px + env(safe-area-inset-bottom));
  width: min(360px, calc(100vw - 24px)); box-sizing: border-box;
  padding: 20px 18px 12px; border-radius: var(--r-xl);
  background: color-mix(in srgb, var(--bg) 96%, transparent); color: var(--label);
  box-shadow: inset 0 1px 0 var(--edge-hi), 0 0 0 .5px var(--edge-lo), 0 20px 60px rgba(0, 0, 0, .5);
  -webkit-backdrop-filter: saturate(180%) blur(24px); backdrop-filter: saturate(180%) blur(24px);
  animation: installin .42s cubic-bezier(.32,.72,0,1) both;
}
@keyframes installin { from { opacity: 0; transform: translateY(24px); } }
.installhero {
  position: relative; width: 56px; height: 56px; margin: 0 auto 12px;
  display: grid; place-items: center; border-radius: var(--r-lg);
  background: var(--fill); color: var(--accent); font-size: 30px;
}
.installhero svg { width: 30px; height: 30px; animation: installpop .42s cubic-bezier(.32,.72,0,1) both; }
@keyframes installpop { from { opacity: 0; transform: scale(.7); } }
/* The toggle switches on while it is shown. */
.installhero[data-step="toggle"] .knob { animation: installknob .5s .6s cubic-bezier(.32,.72,0,1) forwards; }
@keyframes installknob { to { transform: translateX(9px); fill: currentColor; } }
/* A finger's tap: a ring that lands on the glyph and spreads. */
.installtap {
  position: absolute; inset: 50% auto auto 50%; width: 22px; height: 22px; margin: -11px 0 0 -11px;
  border-radius: 50%; border: 2px solid var(--accent); opacity: 0;
  animation: installtap 1.2s .9s ease-out 2;
}
@keyframes installtap { 0% { opacity: .9; transform: scale(.4); } 100% { opacity: 0; transform: scale(2.2); } }
.installhint h2 { margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -.02em; text-align: center; text-wrap: balance; }
.installsub { margin: 4px 0 14px; font-size: 13px; color: var(--label2); text-align: center; }
.installsteps { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.installsteps li {
  display: flex; align-items: center; gap: 12px; min-height: 44px; padding: 4px 10px;
  /* Full-strength text on every step: they are instructions, and a dimmed one
     is the step somebody cannot read when they get to it. */
  border-radius: var(--r-md); color: var(--label);
  transition: background var(--dur-hover) var(--ease-out), color var(--dur-hover) var(--ease-out);
}
.installsteps li.on { background: var(--fill); }
.installico { flex: none; display: grid; place-items: center; width: 24px; font-size: 20px; color: var(--label2); }
.installico svg { width: 20px; height: 20px; }
.installsteps li.on .installico { color: var(--accent); }
.installtxt { font-size: 15px; line-height: 1.3; }
.installtxt b { font-weight: 600; }
/* The hint is what finds a hidden menu, so it keeps most of the text's
   contrast rather than the secondary colour's. */
.installtxt small { display: block; font-size: 12px; color: var(--label); opacity: .78; }
.installlater {
  display: block; margin: 8px auto 0; min-height: 44px; min-width: 44px; padding: 0 16px;
  appearance: none; border: 0; background: none; cursor: default;
  font: inherit; font-size: 15px; color: var(--label2); border-radius: var(--r-md);
}
.installlater:hover { color: var(--label); }
.installlater:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
@media (prefers-reduced-motion: reduce) {
  .installhint, .installhero svg, .installhero[data-step="toggle"] .knob { animation: none; }
  .installtap { display: none; }
}

/* ── phones ──────────────────────────────────────────────────────────────────
   Narrow, or a phone on its side. Width alone sent a landscape iPhone (844pt,
   or 932) to the desktop layout — toolbar, side rail, volume slider and market
   ticker squeezed into 390pt of height, "jumbled" as it was reported. A touch
   screen under 500pt tall is a phone whichever way it is held. The same query
   is in web/phone-bar.js, web/rail-sheet.js and web/sheet.js; the audit keeps
   the four in step. */
@media (max-width: 700px), (pointer: coarse) and (max-height: 500px) {
  /**
   * The globe is the screen; the player and its tabs are the only chrome.
   *
   * After Radio Garden: no title bar at all, a few small controls down the
   * globe's right edge, and a bottom stack of what is playing and where you can
   * go. web/phone-bar.js moves the controls; web/rail-sheet.js drags the sheet.
   */
  .toolbar { display: none; }
  /* dvh, not 100%: in standalone iOS the layout viewport is taller than the
     screen shows, which left a band of dead black under the tab bar. */
  html, body { height: 100dvh; }
  .cols { flex-direction: column; }
  /* Every panel is the same card: half the screen, anchored above the player,
     with the globe still visible over it. A panel that covers the globe is a
     panel you have to leave to see where you are. */
  :root { --panel-h: 52dvh; }
  .globecol { position: absolute; inset: 0; }

  /* What the globe shows, and where to go next: on the globe, out of the way. */
  .globeside {
    position: absolute; top: calc(env(safe-area-inset-top) + 10px); right: 10px; z-index: 5;
    display: flex; flex-direction: column; gap: 8px;
    transition: transform var(--dur-panel) var(--ease-out);
  }
  /* The search field drops in over this corner, so the controls step down. */
  body.searching .globeside { transform: translateY(58px); }
  .globeside button {
    /* 44pt, like every other target here: these three sit over a moving globe,
       which is the last place to ask for a precise tap. */
    width: 44px; height: 44px; display: grid; place-items: center; font-size: 15px;
    border: 0; border-radius: var(--r-lg); cursor: default; color: var(--label);
    background: color-mix(in srgb, var(--bg) 62%, transparent);
    -webkit-backdrop-filter: blur(16px) saturate(1.4); backdrop-filter: blur(16px) saturate(1.4);
    box-shadow: inset 0 0 0 .5px var(--edge-hi), 0 6px 20px rgba(0, 0, 0, .35);
  }
  .globeside button::before { content: none; }
  /**
   * The lock's resting tile.
   *
   * `#lock` is an id and `.globeside button` is a class, so the desktop rule
   * `#lock{background:none}` outranked the tile every button in this column
   * wears: layers and shuffle rested on `--bg` at 62%, the lock on nothing at
   * all, which is why it read as almost invisible beside them. Same id weight
   * here hands it back.
   */
  .globeside #lock { background: color-mix(in srgb, var(--bg) 62%, transparent); }
  /* Resting is quiet, and pressing says so in the palette's colour. */
  .globeside button { color: var(--label2); }
  .globeside button:active, .globeside button.busy { color: var(--accent); }
  /**
   * On is a filled tile, not a tint.
   *
   * Colour alone cannot carry this: in Onyx the accent *is* bone, the same
   * value as the resting glyph, so a locked station looked exactly like an
   * unlocked one — pressing it appeared to do nothing. Filled, it reads in all
   * nine palettes, and the glyph flips to the colour that sits on the accent.
   */
  .globeside button[aria-pressed="true"],
  .globeside #lock[aria-pressed="true"],
  .globeside #layersBtn[aria-pressed="true"] {
    color: var(--on-accent); background: var(--accent);
    box-shadow: inset 0 0 0 .5px var(--edge-hi), 0 6px 20px rgba(0, 0, 0, .35);
  }

  /* Search is a tab, so the field appears when that tab is on. */
  .searchbar {
    /* Full width, like the sheet, and its field starts on the same text column
       the station names do — the two were a few pixels out of step. */
    position: fixed; left: 0; right: 0; top: 0; z-index: 9;
    padding: calc(env(safe-area-inset-top) + 8px) 17px 12px;
    background: color-mix(in srgb, var(--bg) 94%, transparent);
    -webkit-backdrop-filter: blur(20px) saturate(1.4); backdrop-filter: blur(20px) saturate(1.4);
    box-shadow: 0 8px 24px rgba(0, 0, 0, .3);
  }
  .searchbar[hidden] { display: none; }
  .searchbar #q { width: 100%; height: 40px; border-radius: var(--r-lg); }

  /**
   * The station sheet: edge to edge, and flush with the player.
   *
   * It was inset with rounded sides, which drew a seam between the list and
   * the row under it and left a strip of globe nobody could use. Full width,
   * rounded only where you grab it, and its bottom runs behind the player.
   */
  .railcol {
    position: absolute; left: 0; right: 0; bottom: 0; top: auto;
    width: auto; height: 92%; gap: 0; z-index: 4;
    transform: translate3d(0, var(--sheet-y, 42%), 0);
  }
  /**
   * One thing in the panel area at a time.
   *
   * Headlines and chat used to float over a sheet still showing the last place
   * or the favourites list, so two answers to "what am I looking at" were on
   * screen at once. While either is open the sheet stands down; Explore and
   * Favourites are the sheet, so they leave it up.
   */
  body.panel-open .railcol { display: none; }
  .sheetgrab, .placehead { touch-action: none; }
  .scroll, .newslist, #chatlog, .convos, .chips { overscroll-behavior: contain; }
  .railcol.sliding { transition: none; }
  .railcol.settling { transition: transform .42s cubic-bezier(.32,.72,0,1); }
  @media (prefers-reduced-motion: reduce) { .railcol.settling { transition: none; } }
  .stations {
    flex: 1; min-height: 0; padding-top: 18px;
    border-radius: var(--r-xl) var(--r-xl) 0 0;
    background: color-mix(in srgb, var(--bg) 96%, transparent);
    box-shadow: inset 0 1px 0 var(--edge-hi), 0 -10px 40px rgba(0, 0, 0, .45);
  }
  .sheetgrab {
    display: grid;
    /* 44pt of button with the pill drawn at the top of it: the target is the
       size a thumb needs to catch a sheet, the drawing is a hairline. */
    position: absolute; top: 0; left: 0; right: 0; height: 44px;
    appearance: none; border: 0; background: none; padding: 0; cursor: default;
    place-items: start center; z-index: 1;
  }
  .sheetgrab::before {
    content: ""; margin-top: 7px; width: 36px; height: 5px;
    border-radius: var(--r-pill); background: var(--label3);
  }
  .sheetgrab:focus-visible { outline: 2px solid var(--accent); outline-offset: -4px; border-radius: var(--r-xl); }

  /* Rows at a phone's rhythm: 46pt fits six where 58 fit four, and the star
     gives its spare width back to the name. */
  #stationlist .st, #placelist .place { padding: 2px 10px; min-height: 46px; }
  /* The tags scroll sideways, so they run to the screen's edge rather than
     stopping at the heading's margin with the last one cut in half. */
  .placehead .chips { margin-right: -17px; padding-right: 17px; }
  .st .star { min-width: 34px; min-height: 34px; font-size: 13px; margin-right: 0; }

  /* Read-outs belong to the globe, so they ride above the sheet's top edge. */
  /* The read-out belongs to the globe, so it rides just above the sheet rather
     than up among the status bar's own clock and battery. --peek is how much
     sheet is showing (web/rail-sheet.js). */
  .globebar { right: 0; top: auto; bottom: calc(var(--peek, 40%) + 8px); padding-bottom: 0; }

  /**
   * What is playing: one row, and the whole row is the way back to the list.
   *
   * `.nowopen` is a real button laid under the text — the row used to be a div
   * with a click handler, which is a control that exists for a finger and not
   * for a keyboard or VoiceOver. The transport sits above it.
   */
  body.phonebar .now {
    position: relative; z-index: 5; gap: 10px; font-size: 14px;
    padding: 8px 12px 8px 14px;
    background: color-mix(in srgb, var(--bg) 94%, transparent);
    -webkit-backdrop-filter: blur(20px) saturate(1.4); backdrop-filter: blur(20px) saturate(1.4);
    box-shadow: inset 0 .5px 0 var(--line);
  }
  .nowopen {
    position: absolute; inset: 0; z-index: 0;
    appearance: none; border: 0; background: none; padding: 0; cursor: default;
  }
  .nowopen:focus-visible { outline: 2px solid var(--accent); outline-offset: -3px; }
  body.phonebar .now > *:not(.nowopen) { position: relative; z-index: 1; }
  body.phonebar .now .brand svg { height: 15px; }
  body.phonebar .now b { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  body.phonebar .now #nowStatus { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* Volume and the output picker belong to iOS here: the hardware keys set one
     and Control Centre sets the other, from outside any app. */
  body.phonebar .now .volwrap, body.phonebar .now #nowStar, body.phonebar .now .outwrap,
  body.phonebar .now .brand { display: none; }
  /* Sharing works here after all: the card goes into the system's share sheet
     rather than needing a clipboard and a file dialog of our own. */
  body.phonebar .now #nowShare {
    display: grid !important; place-items: center; flex: none;
    width: 32px; height: 32px; min-width: 32px; min-height: 32px;
    font-size: 13px; color: var(--label2);
    background: none; border: 0; border-radius: var(--r-md); cursor: default;
  }
  body.phonebar .now #nowShare[hidden] { display: none !important; }
  body.phonebar .now #nowShare:active { background: var(--fill); }
  /* Drawn at 32 to match lock and play; caught at 44, as play is below. */
  body.phonebar .now #nowShare::before { content: ""; position: absolute; inset: -6px; border-radius: var(--r-md); }
  /* 34pt: the row is a strip, and a 40pt disc in it read as a button with a
     line of text beside it rather than a line of text you can play. */
  /* 30pt: a shade bigger than the line of type beside it, which is what a
     control inside a strip should be. Lock and share match, so the three read
     as one set acting on one station. */
  body.phonebar .now #play {
    margin-left: auto; width: 30px; height: 30px; min-width: 30px; min-height: 30px;
    font-size: 11px;
  }
  /* The ring stays 30px; the target around it is 44. Play is the one control
     on this row everybody uses, and it was the smallest thing on the screen. */
  body.phonebar .now #play::before { content: ""; position: absolute; inset: -7px; border-radius: 50%; }
  body.phonebar .now #lock {
    flex: none; width: 32px; height: 32px; min-width: 32px; min-height: 32px;
    display: grid; place-items: center; padding: 0; font-size: 13px;
  }

  /* ── the tabs ─────────────────────────────────────────────────────────────
     Five, labelled, because an unexplained row of glyphs is a quiz — and five
     is the ceiling every platform's guidance sets. */
  .tabbar {
    position: relative; z-index: 5; flex: none;
    display: flex; align-items: stretch; justify-content: space-between;
    /* The home indicator's strip is already empty space; the bar does not need
       to add its own on top, so it keeps only what is left after 8pt of it. */
    padding: 3px 4px max(2px, calc(env(safe-area-inset-bottom) - 8px));
    background: color-mix(in srgb, var(--bg) 94%, transparent);
    -webkit-backdrop-filter: blur(20px) saturate(1.4); backdrop-filter: blur(20px) saturate(1.4);
    box-shadow: inset 0 .5px 0 var(--line);
  }
  .tabbar[hidden] { display: none; }
  .tab {
    flex: 1; min-height: 46px; display: grid; gap: 2px; place-items: center;
    appearance: none; border: 0; background: none; padding: 4px 2px; cursor: default;
    color: var(--label2); font: inherit;
  }
  .tabicon { display: grid; place-items: center; font-size: 17px; line-height: 1; }
  /* 12px is the floor for text meant to be read; five words at that size fit a
     375pt screen with Headlines, the longest, still clear of its neighbours. */
  .tablabel { font-size: 12px; letter-spacing: -.004em; white-space: nowrap; }
  .tab[aria-pressed="true"] { color: var(--accent); }
  .tab:active { opacity: .6; }
  .tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -3px; border-radius: var(--r-md); }

  /* ── panels ───────────────────────────────────────────────────────────────
     Headlines, layers and chat all arrive from the bottom, full width, and
     stop where the player's chrome begins (--chrome, measured in JS). */
  .newspanel, #layers, .chatpanel {
    position: fixed; left: 0; right: 0; top: auto; width: auto;
    /**
     * Behind the chrome, not over it.
     *
     * These were z-index 6 against the bar's 5, stopping just short of it and
     * throwing an 18px downward shadow across it — which reads as a card
     * hovering over the app rather than content the bar sits on top of.
     * Favourites always looked right because the rail sheet is z-index 4,
     * under the chrome, running on underneath it. This is that, exactly.
     *
     * Growing the height by --chrome while anchoring to the bottom keeps the
     * top edge where it already was; only the far end now passes behind.
     */
    bottom: 0; z-index: 4;
    height: calc(var(--panel-h) + var(--chrome, 0px));
    max-height: calc(var(--panel-h) + var(--chrome, 0px));
    overflow-y: auto; overscroll-behavior: contain;
    /* So the last row can still be scrolled out from behind the bar. */
    padding-bottom: var(--chrome, 0px);
    border-radius: var(--r-xl) var(--r-xl) 0 0;
    /* Upward, onto the globe. A downward blur lands on the bar, which is the
       shadow this whole rule exists to stop casting. */
    box-shadow: inset 0 1px 0 var(--edge-hi), 0 -10px 40px rgba(0, 0, 0, .45);
  }
  .newshead { padding-left: 14px; }
  /**
   * Headlines, Chat and Favourites work as Settings does: a handle to pull,
   * the heading pulls too, and the panel's own tab closes it. So no × here —
   * it was the only way out of Headlines, and on a phone the thumb already
   * knows two better ones. The source button (now a globe) takes its place.
   */
  #newsClose { display: none; }
  /**
   * One heading style for every panel on a phone.
   *
   * Favourites, Explore ("12,579 places") and Chat head their panels in the
   * small section style — 11px, 590, the secondary label colour. Settings and
   * Headlines were the two that shouted: 17px and 19px, bold. Same as the rest
   * now, so a title says which panel this is without being the loudest thing
   * in it. The wide layouts keep their headings.
   */
  .newshead b, .setsheet-head h2 {
    font-size: 11px; font-weight: 590; letter-spacing: .005em; line-height: 1.4; color: var(--label2);
  }
  /* The desktop's slide-in from the left. Here the panel rises on Settings'
     spring (web/sheet.js), and a CSS animation owns the transform while it
     runs — the two fought, and the sheet faded sideways, then jumped. */
  .newspanel { animation: none; }
  .panelgrab {
    display: block; position: sticky; top: 0; z-index: 2; height: 18px; flex: none;
    touch-action: none; cursor: grab;
  }
  .panelgrab::before {
    content: ""; display: block; width: 36px; height: 5px; margin: 6px auto 0;
    border-radius: var(--r-pill); background: var(--label3);
  }
  .newshead, .chathead, .placebar { touch-action: none; }
  /* The sheet pulled all the way up reaches the globe's buttons at the top
     right; they step aside rather than sit over the list and its sort. */
  .globeside { transition: transform var(--dur-panel) var(--ease-out), opacity var(--dur-control) var(--ease-out); }
  /* visibility, not just opacity: invisible buttons must leave the tab order
     too. Delayed by the fade, so they still fade rather than vanish. */
  body.sheet-open .globeside {
    opacity: 0; visibility: hidden; pointer-events: none;
    transition: transform var(--dur-panel) var(--ease-out), opacity var(--dur-control) var(--ease-out),
                visibility 0s linear var(--dur-control);
  }
  .chatpanel {
    display: flex; flex-direction: column; overflow: hidden;
    height: calc(var(--panel-h) + var(--chrome, 0px));
    background: color-mix(in srgb, var(--bg) 96%, transparent);
    -webkit-backdrop-filter: blur(24px) saturate(1.4); backdrop-filter: blur(24px) saturate(1.4);
    box-shadow: inset 0 1px 0 var(--edge-hi), 0 -10px 40px rgba(0, 0, 0, .45);
  }
  .chatpanel[hidden] { display: none; }
  .chatpanel:has(#chat[hidden]) { height: auto; }
  .chatpanel #chat { flex: 1; max-height: none; box-shadow: none; background: none; }
  .chatpanel .chatnone { display: none; margin: 0; padding: 30px 20px; text-align: center;
    color: var(--label2); font-size: 14px; line-height: 1.5; }
  .chatpanel #chat[hidden] + .chatnone { display: block; }

  /**
   * Settings is a card like the others.
   *
   * It came up as a full-height sheet, which is the one thing every panel here
   * agreed not to do: cover the globe. Same height, same corner, same place —
   * it just has more in it, so it scrolls.
   */
  /**
   * 9800 put the whole sheet, scrim included, over the tab bar. On a phone it
   * is one of the five tabs, so it belongs under the bar that switched to it.
   *
   * And under it for taps as well, which z-index alone does not deliver: the
   * panel's surface runs behind the chrome by design, and a box that lies over
   * the bar takes the tap whatever its z-index says — an iframe especially.
   * That is why every other tab was dead while Settings was open, and Done
   * really was the only way out. So nothing in the sheet catches a pointer
   * except the parts you actually press, and the scrim stops above the chrome.
   */
  .setsheet { z-index: 4; pointer-events: none; }
  .setsheet-scrim { pointer-events: auto; bottom: var(--chrome, 0px); }
  .setsheet-panel { pointer-events: none; }
  .setsheet-grab, .setsheet-head, .setsheet-frame { pointer-events: auto; }
  .setsheet-panel {
    left: 0; right: 0; top: auto; bottom: 0; translate: none; width: auto;
    height: calc(var(--panel-h) + var(--chrome, 0px));
    /**
     * The surface runs behind the chrome; the settings themselves stop above
     * it. Without this the iframe reached the bottom of the screen and sat
     * over the tab bar — and an iframe takes the tap wherever it lies, whatever
     * the z-index says, so every tab was dead while Settings was open and the
     * Done button really was the only way out. The other panels got this
     * padding when they moved behind the bar; this one was missed.
     */
    padding-bottom: var(--chrome, 0px);
    border-radius: var(--r-xl) var(--r-xl) 0 0;
    opacity: 1; transform: translateY(100%); transition: none;
  }
  .setsheet.open .setsheet-panel { transform: translateY(0); }
  .setsheet.open .setsheet-scrim { opacity: var(--dim, 1); transition: none; }
  .setsheet-grab { display: block; }
  .setsheet-head, .setsheet-grab { touch-action: none; }
  /* No Done on a phone. The bar is always live under the sheet now, so there
     were three ways out — another tab, pulling it down, and Done — and on a
     phone the first two are what every other app has taught. Wide screens keep
     it: there is no tab bar there, and it is the only visible way out. */
  .setsheet-done { display: none; }
  /* Done was what gave the header its height, and the header is also the drag
     handle — so it keeps a finger's height without it. */
  .setsheet-head { min-height: 44px; box-sizing: border-box; }
  /* The scrim would blacken the planet this is supposed to sit over. */
  .setsheet-scrim { background: rgba(0, 0, 0, .28); }

  /* Solid for anyone who asked for less transparency or more contrast: this
     chrome sits over a planet, which is the worst case for text on glass. */
  @media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
    .tabbar, body.phonebar .now, .chatpanel, .searchbar, .globeside button, .stations,
    /* #layers blurs like the rest of them and had been left out of this list. */
    #layers {
      background: var(--bg); -webkit-backdrop-filter: none; backdrop-filter: none;
    }
    /* An id to beat an id: the resting-tile rule above is `.globeside #lock`,
       which would otherwise keep its glass here while its two neighbours went
       solid — the same mismatch, wearing the accessibility setting. */
    .globeside #lock { background: var(--bg); }
  }

  /**
   * The share sheet, on a phone.
   *
   * It is a centred card sized for a window: on a Mini the buttons wrapped and
   * the card overflowed. Here it comes up from the bottom like everything else,
   * the card fits the width it is given, and the buttons are a row you can hit.
   * Most phones never see it — sharing goes to the system sheet — but a browser
   * without one falls back here.
   */
  .sheet { place-items: end stretch; }
  .sheetbox {
    width: 100%; max-height: 92dvh; gap: 10px;
    padding: 12px 12px calc(12px + env(safe-area-inset-bottom));
    border-radius: var(--r-xl) var(--r-xl) 0 0; border: 0;
    background: color-mix(in srgb, var(--bg) 96%, transparent);
  }
  #sheetimg { max-height: 58dvh; max-width: 100%; }
  .sheetrow { width: 100%; gap: 6px; }
  .sheetbtn { flex: 1; min-height: 44px; font-size: 13px; padding: 7px 8px; }

  /* Safari zooms into any field under 16px when it is tapped. Only a touch
     screen zooms, and the pointer has to be asked: Settings is an iframe about
     560px wide, so on a laptop it answers this block's width question too. */
  @media (pointer: coarse) { input, select, textarea { font-size: 16px !important; } }
  #vol, .markets { display: none !important; }
}

/* ── touch ─────────────────────────────────────────────────────────────────── */
/**
 * Hover does not exist here, and a phone fakes it.
 *
 * Touch browsers leave :hover applied to the last thing tapped, so every
 * hover style became a highlight stuck under your finger's last stop —
 * a row that looks selected when nothing is. The press states stay.
 */
@media (hover: none) {
  .toolbar button:hover::before { background: var(--fill); }
  .st:hover, .place:hover, .story:hover, .layrow:hover, .convos .row:hover,
  .chips button:hover { background: none; }
  .toolbar button[aria-pressed="true"]::before { background: var(--fill-hi); }
}

/* ── touch ─────────────────────────────────────────────────────────────────── */
/* 44 points is the smallest target a finger hits reliably. */
@media (pointer: coarse) {
  .toolbar button, #play, #lock, #mute, #nowStar, #outbtn, .star, .newshead button {
    min-width: 44px; min-height: 44px;
  }
  /* The filter chips are a scrolling row of pills; 44pt pills would crowd out
     the list they filter, so they get the tallest target the row can hold. */
  .chips { height: auto; padding: 2px 0; }
  .chips button { min-height: 34px; padding-inline: 12px; }
  .st, .place, .story { min-height: 44px; }
  .layrow { min-height: 44px; }
  /* Hover never comes on a touch screen, so the star is always there. */
  .st .star { opacity: 1; }
}

/* ── the Settings page, inside the sheet ──────────────────────────────────── */
/* The sheet's own header says "Settings" and holds Done, so the page's title
   and the Mac title-bar spacer go. */
html.embedded .titlebar, html.embedded main > h1 { display: none; }
html.embedded main { padding-top: 14px; padding-bottom: calc(22px + env(safe-area-inset-bottom)); }

/* ── a phone on its side ──────────────────────────────────────────────────────
   The phone layout, with two things portrait never needs. The notch is on the
   left or the right, so everything that runs edge to edge keeps clear of it —
   the globe itself is the only thing that should go under it. And 52% of 375pt
   left Settings about 150pt for its contents, so panels take more of the height
   here: 62%, which still leaves the globe a strip above them. */
@media (pointer: coarse) and (max-height: 500px) and (orientation: landscape) {
  :root { --panel-h: 62dvh; }
  /* max(): on a phone with no notch the inset is 0, and each bar keeps the
     padding it already had rather than losing it. */
  .tabbar { padding-left: max(4px, env(safe-area-inset-left)); padding-right: max(4px, env(safe-area-inset-right)); }
  body.phonebar .now { padding-left: max(14px, env(safe-area-inset-left)); padding-right: max(12px, env(safe-area-inset-right)); }
  .searchbar { padding-left: max(17px, env(safe-area-inset-left)); padding-right: max(17px, env(safe-area-inset-right)); }
  .railcol, .newspanel, .chatpanel, .setsheet-panel {
    padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right);
  }
  .globeside { right: calc(env(safe-area-inset-right) + 10px); }
  /* 360pt tall, so any panel reaches the globe's three buttons at the right —
     and they are drawn above it: they sat over the list's filter button and
     over Headlines, Chat and Settings. While a panel is up they step aside. */
  body.sheet-held .globeside, body.panel-open .globeside, body:has(.setsheet:not([hidden])) .globeside {
    opacity: 0; visibility: hidden; pointer-events: none;
    transition: opacity var(--dur-control) var(--ease-out), visibility 0s linear var(--dur-control);
  }
}
