/* --------------------------------------------------------------------------
   Link colour
   --------------------------------------------------------------------------
   The theme's --aqua is a pale mint. It reads beautifully on the night
   surface (12.6:1) and is nearly invisible on the day one: #7ef0d5 on #ffffff
   measures 1.37:1, far below the 4.5:1 WCAG asks for body text. --aqua-deep
   is commented in tokens.css as the "on-light text-safe variant" but measures
   1.77:1, so that note is wrong and should not be trusted.

   --blue-ink is already defined per theme (#1a5fae day, #8fc2ff night) and
   measures 6.38:1 on the day surface and 9.33:1 on the night one, so links
   take it and stay legible in both. Aqua is kept for fills and icons, where
   it sits behind --on-accent text rather than acting as text itself.

   Recompute before changing this: relative luminance, not appearance.
   -------------------------------------------------------------------------- */
.dt-block,
.dt-stage,
.dt-report {
  --dt-link: var(--blue-ink);
}

/* ==========================================================================
   Device & browser test — page layer
   --------------------------------------------------------------------------
   Sits on top of tokens.css / base.css / shell.css / components.css from the
   Lake Mead Admin theme. Everything here reads those tokens: no literal
   colours, so the page follows the day/night switch without a second palette.

   Two things this file owns that the theme has no equivalent for:
     1. Sidebar nav items that are checkboxes (the device catalogue).
     2. The preview stage — frames held at true device size and scaled by
        transform, with a fold crease drawn over them.
   ========================================================================== */

/* --- Sidebar: devices as selectable nav items --------------------------- */

/* The native checkbox stays in the accessibility tree and keeps keyboard
   behaviour; it is only visually replaced, never removed. */
.dt-device > input[type="checkbox"] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.dt-device {
  cursor: pointer;
  position: relative;
  align-items: flex-start;
}

/* The tick and icon stay on the first line when the name wraps. */
.dt-device .nav-link__icon,
.dt-device__check {
  margin-top: 1px;
}

/* The theme sets `.nav-link__text { overflow: hidden; text-overflow: ellipsis }`
   for short single-line nav labels. Device names are longer than that allows
   — "iPhone Duo — unfolded" was clipped to "iPhone Duo — " — so the clipping
   is lifted here and the name wraps to a second line instead. */
.dt-device .nav-link__text {
  display: flex;
  flex-direction: column;
  line-height: 1.25;
  min-width: 0;
  overflow: visible;
  text-overflow: clip;
}

.dt-device__name {
  overflow-wrap: break-word;
  white-space: normal;
}

/* The sidebar is LIGHT in day (--sidebar-bg is --paper-warm, #ebece6) and
   dark in night. Aqua measures 1.15:1 on that light rail, so these accents
   take --blue-ink, which is defined per theme and clears 5:1 on both. Aqua is
   still right where it is a fill behind --on-accent text, such as the tick
   and the fold pill in the main column. */
.dt-device__fold {
  color: var(--blue-ink);
  font-weight: 600;
}

.dt-device__size {
  color: var(--muted);
  font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10.5px;
  letter-spacing: 0.01em;
}

/* The tick reads as the selected state. It replaces the theme's active-page
   treatment, which is meant for "where am I", not "what is chosen". */
.dt-device__check {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  margin-left: auto;
  color: transparent;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 6px;
  font-size: 10px;
  transition: background-color .16s ease, border-color .16s ease, color .16s ease;
}

.dt-device:hover .dt-device__check {
  border-color: var(--aqua);
}

.dt-device:has(input:checked) .dt-device__check {
  color: var(--on-accent);
  background: var(--aqua);
  border-color: var(--aqua);
}

.dt-device:has(input:checked) .nav-link__text {
  color: var(--ink);
  font-weight: 600;
}

.dt-device:has(input:checked) .nav-link__icon {
  color: var(--blue-ink);
}

.dt-device:has(input:focus-visible) {
  outline: 2px solid var(--aqua);
  outline-offset: -2px;
}

/* Section collapsing.

   shell.css carries the rule that actually hides a nav section, and its own
   comment says it is "THE ONLY PLACE SECTION SLUGS ARE LISTED" — the selector
   enumerates the admin theme's sections by name. This page invents its own
   slugs, so without the matching rules below the group chevrons would toggle
   aria-expanded and persist state while nothing ever collapsed. Add a slug to
   devices.php and it needs a line here too. */
html[data-nav-collapsed~="foldable"] .nav-section[data-section="foldable"],
html[data-nav-collapsed~="iphone"]   .nav-section[data-section="iphone"],
html[data-nav-collapsed~="ipad"]     .nav-section[data-section="ipad"],
html[data-nav-collapsed~="android"]  .nav-section[data-section="android"],
html[data-nav-collapsed~="desktop"]  .nav-section[data-section="desktop"],
html[data-nav-collapsed~="site"]     .nav-section[data-section="site"] {
  --list-h: 0px;
  --list-op: 0;
  --caret-rot: -90deg;
}

/* A collapsed sidebar hides label text; the tick would otherwise sit alone in
   the middle of the rail, so it moves to a corner dot instead.

   The theme marks this state as `body.is-collapsed` (see shell.js), not a
   class on the sidebar — an earlier guess at `.sidebar.is-collapsed` matched
   nothing, leaving full-size tick boxes crowding the narrow rail. */
body.is-collapsed .dt-device__check {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  font-size: 0;
}

.sidebar__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 12px;
  border-top: 1px solid var(--line-soft);
}

.dt-selected-count {
  color: var(--muted);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11px;
}

/* --- Topbar address field ----------------------------------------------- */

.dt-url-form {
  display: flex;
  align-items: center;
  gap: 8px;
}

.dt-url-form input[type="url"] {
  flex: 1;
  min-width: 0;
  color: inherit;
  background: none;
  border: 0;
  font: inherit;
  outline: none;
}

.dt-url-form .btn {
  flex: 0 0 auto;
}

/* --- Page-head switches -------------------------------------------------- */

.dt-switches {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.dt-switch {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 12px;
  cursor: pointer;
  color: var(--ink-soft);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 13px;
  transition: border-color .16s ease, color .16s ease;
}

.dt-switch input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.dt-switch__box {
  display: grid;
  place-items: center;
  width: 16px;
  height: 16px;
  color: transparent;
  border: 1px solid var(--line);
  border-radius: 5px;
  font-size: 9px;
  transition: background-color .16s ease, border-color .16s ease, color .16s ease;
}

.dt-switch:hover {
  border-color: var(--aqua);
}

.dt-switch:has(input:checked) {
  color: var(--ink);
  border-color: var(--aqua);
}

.dt-switch:has(input:checked) .dt-switch__box {
  color: var(--on-accent);
  background: var(--aqua);
  border-color: var(--aqua);
}

.dt-switch:has(input:focus-visible) {
  outline: 2px solid var(--aqua);
  outline-offset: 2px;
}

/* --- Section blocks ------------------------------------------------------ */

.dt-block {
  margin-bottom: 28px;
}

.dt-block__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px 20px;
  margin-bottom: 12px;
}

.dt-block__title {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0;
  font-size: 17px;
  font-weight: 700;
}

/* This icon sits on the light main column in day mode, where aqua measures
   1.37:1 and effectively disappears. The sidebar keeps aqua because its
   surface is dark in both themes. */
.dt-block__title i {
  color: var(--dt-link, var(--blue-ink));
  font-size: 14px;
}

.dt-block__note {
  margin: 0;
  max-width: 62ch;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}

/* --- Preview stage ------------------------------------------------------- */

/* The stage is a striped table of device rows rather than a horizontal
   filmstrip. Side by side, a 466px folded Duo and an 890px unfolded one had
   to be scrolled between to compare; stacked, they share one viewport column
   and line up under each other. */
.dt-stage {
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-lg, 14px);
}

.dt-frame {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 0;
  padding: 20px 24px;
  border-bottom: 1px solid var(--line-soft);
}

.dt-frame:last-child {
  border-bottom: 0;
}

/* The alternating band. color-mix keeps it a tint of the surface already in
   use, so it holds in both day and night without a second hard-coded value. */
.dt-frame:nth-child(even) {
  background: color-mix(in srgb, var(--ink) 4%, transparent);
}

/* Device name across the top of its row. */
.dt-frame-title {
  display: flex;
  align-items: center;
  gap: 9px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line-soft);
}

.dt-frame-name {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

/* Marks a device whose viewport spans a physical seam. */
.dt-frame-foldtag {
  padding: 2px 8px;
  color: var(--on-accent);
  background: var(--aqua);
  border-radius: 999px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.dt-frame-view-col {
  min-width: 0;
}

/* Numbers and actions sit under the frame. */
/* Actions first and hard left, with the specs following. They were pushed to
   the far right by space-between, which left them stranded across an empty
   row from everything else. */
.dt-frame-info {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: 8px 22px;
  padding-top: 10px;
  border-top: 1px solid var(--line-soft);
}

.dt-frame-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 12px;
  min-width: 0;
}

.dt-frame-name {
  font-size: 14px;
  font-weight: 650;
}

.dt-frame-spec,
.dt-frame-note {
  color: var(--muted);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 10.5px;
}

/* The shell reserves the scaled footprint; the scaler inside holds the frame
   at true device size and is transformed down to fit. The embedded page
   measures the untransformed size, which is the entire point of the tool. */
.dt-frame-shell {
  position: relative;
  overflow: hidden;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: var(--shadow-md);
}

.dt-frame-scaler {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
}

.dt-frame-view {
  display: block;
  width: 100%;
  height: 100%;
  background: #fff;
  border: 0;
}

/* --- Nothing loaded yet ---------------------------------------------------
   Shown in place of the iframe before an address is entered. The shell is
   white so a real preview starts on the page's own background rather than a
   grey one, but an empty frame has no page in it — so it takes the surface
   colour instead of sitting there as a white rectangle, which read as a
   broken preview rather than an empty one.
   -------------------------------------------------------------------------- */
.dt-frame-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  height: 100%;
  padding: 24px;
  text-align: center;
  background: var(--surface-alt, var(--surface));
  /* The dashes read as a placeholder: an area waiting for content, not a
     panel that is finished. */
  border: 1px dashed var(--line);
  border-radius: 11px;
}

.dt-frame-empty__mark {
  color: var(--aqua);
  opacity: .85;
  /* A slow rise toward the address bar it is pointing at. */
  animation: dt-empty-nudge 2.8s ease-in-out infinite;
}

@keyframes dt-empty-nudge {
  0%, 100% { transform: translateY(2px); }
  50%      { transform: translateY(-3px); }
}

.dt-frame-empty__title {
  margin: 0;
  color: var(--ink);
  font-size: 14.5px;
  font-weight: 650;
}

.dt-frame-empty__body {
  max-width: 30ch;
  margin: 0;
  color: var(--muted);
  font-size: 12.5px;
  line-height: 1.55;
}

/* A folded-phone frame is only 466px wide but a desktop one is 1280 — the
   copy would look lost in the latter, so it stays centred and capped. */
@media (prefers-reduced-motion: reduce) {
  .dt-frame-empty__mark {
    animation: none;
  }
}

/* The crease guide. Two hairlines and a soft core read as a seam without
   pretending to be a hinge the embedded page can detect — it cannot. */
.dt-crease {
  position: absolute;
  pointer-events: none;
}

.dt-crease-vertical {
  top: 0;
  bottom: 0;
  width: 3px;
  margin-left: -1px;
  background: linear-gradient(to right,
    rgba(0, 0, 0, .20), rgba(0, 0, 0, .05), rgba(0, 0, 0, .20));
}

.dt-crease-horizontal {
  left: 0;
  right: 0;
  height: 3px;
  margin-top: -1px;
  background: linear-gradient(to bottom,
    rgba(0, 0, 0, .20), rgba(0, 0, 0, .05), rgba(0, 0, 0, .20));
}

/* Click-to-interact guard.

   A tall frame sits in the middle of a scrolling page. With the iframe live,
   a wheel event over it scrolls the embedded site and never chains back out,
   so the visitor gets stuck at the preview and cannot reach the report below.
   The guard is a transparent sheet that takes those events instead; clicking
   it hands the frame over for real interaction. */
.dt-frame-guard {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  cursor: pointer;
  background: transparent;
  border: 0;
  padding: 0;
}

.dt-frame-guard__hint {
  padding: 7px 13px;
  color: var(--ink);
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  border: 1px solid var(--line);
  border-radius: 999px;
  box-shadow: var(--shadow-md);
  font-size: 12px;
  font-weight: 600;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity .16s ease, transform .16s ease;
}

.dt-frame-guard:hover .dt-frame-guard__hint,
.dt-frame-guard:focus-visible .dt-frame-guard__hint {
  opacity: 1;
  transform: translateY(0);
}

.dt-frame-guard:focus-visible {
  outline: 2px solid var(--aqua);
  outline-offset: -2px;
}

/* Once live, say so, and give the frame a way back to the guarded state. */
.dt-frame-live .dt-frame-shell {
  outline: 2px solid var(--aqua);
  outline-offset: 2px;
}

.dt-frame-release {
  align-self: flex-start;
  padding: 0;
  color: var(--dt-link, var(--blue-ink));
  cursor: pointer;
  background: none;
  border: 0;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
}

.dt-frame-release:hover { text-decoration: underline; }

@media (prefers-reduced-motion: reduce) {
  .dt-frame-guard__hint { transition: none; }
}

/* The blocked-frame overlay.

   `hidden` hides an element via `display: none` in the UA stylesheet, which
   ANY author `display` declaration outranks. The first version of this rule
   set `display: flex` without the [hidden] guard below, so the 96% opaque
   panel stayed on top of every preview and washed each site out to near
   white. Keep these two rules adjacent, and never verify the overlay by
   reading `.hidden` alone — that property read false while the panel was
   plainly on screen. Check computed `display`. */
.dt-frame-block[hidden] {
  display: none;
}

.dt-frame-block {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 9px;
  padding: 22px;
  color: var(--ink);
  background: var(--surface);
  font-size: 13px;
  line-height: 1.5;
}

.dt-frame-block strong {
  font-size: 15px;
}

.dt-frame-open {
  color: var(--dt-link, var(--blue-ink));
  font-size: 12px;
  font-weight: 600;
  text-decoration: none;
}

.dt-frame-open:hover {
  text-decoration: underline;
}

/* --- Per-browser report -------------------------------------------------- */

.dt-report-summary {
  margin: 0 0 16px;
  padding: 12px 14px;
  background: color-mix(in srgb, var(--aqua) 10%, transparent);
  border-left: 3px solid var(--aqua);
  border-radius: 8px;
  font-size: 13.5px;
  line-height: 1.55;
}

.dt-results {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
  gap: 18px;
}

.dt-result {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.dt-result-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.dt-result-title {
  margin: 0;
  font-size: 15.5px;
  font-weight: 650;
}

.dt-result-message {
  margin: 0;
  color: var(--rose, var(--ink));
  font-size: 13.5px;
}

.dt-result-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 16px;
  margin: 0;
}

.dt-result-stats > div {
  padding: 8px 0;
  border-top: 1px solid var(--line-soft);
}

.dt-result-stats dt {
  margin-bottom: 2px;
  color: var(--muted);
  font-size: 10px;
  letter-spacing: .07em;
  text-transform: uppercase;
}

.dt-result-stats dd {
  margin: 0;
  overflow-wrap: anywhere;
  font-size: 13px;
  line-height: 1.4;
}

.dt-viewport-tag,
.dt-redirects {
  display: grid;
  gap: 6px;
}

.dt-viewport-label {
  color: var(--muted);
  font-size: 10px;
  letter-spacing: .07em;
  text-transform: uppercase;
}

.dt-viewport-tag code,
.dt-redirects code,
.dt-queries code {
  display: block;
  padding: 7px 9px;
  overflow-wrap: anywhere;
  background: var(--surface-alt, var(--surface));
  border: 1px solid var(--line-soft);
  border-radius: 7px;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11.5px;
  line-height: 1.45;
}

.dt-result-notes {
  display: grid;
  gap: 8px;
  padding: 0;
  margin: 0;
  list-style: none;
}

.dt-note {
  display: grid;
  grid-template-columns: 19px minmax(0, 1fr);
  gap: 9px;
  align-items: start;
  font-size: 13px;
  line-height: 1.5;
}

.dt-note-mark {
  display: grid;
  place-items: center;
  width: 19px;
  height: 19px;
  border-radius: 50%;
  font-size: 11px;
  font-weight: 700;
}

.dt-note-bad .dt-note-mark {
  color: var(--on-accent, #fff);
  background: var(--rose, #e05260);
}

.dt-note-warn .dt-note-mark {
  color: var(--ink);
  background: color-mix(in srgb, var(--sun, #e0a800) 45%, transparent);
}

.dt-framing {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
}

.dt-framing-ok { color: var(--dt-link, var(--blue-ink)); }
.dt-framing-blocked { color: var(--rose, var(--ink)); }

.dt-queries { font-size: 13px; }

.dt-queries summary {
  cursor: pointer;
  color: var(--dt-link, var(--blue-ink));
  font-weight: 600;
}

.dt-queries code { margin-top: 6px; }

.dt-queries-note {
  margin: 9px 0 0;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.45;
}

/* --- Notes and placeholders ---------------------------------------------- */

.dt-notes {
  display: grid;
  gap: 12px;
  max-width: 88ch;
  padding: 0;
  margin: 0;
  list-style: none;
}

.dt-notes li {
  padding-left: 14px;
  border-left: 2px solid var(--line);
  color: var(--ink-soft);
  font-size: 13.5px;
  line-height: 1.6;
}

.dt-notes strong { color: var(--ink); }

.dt-notes code,
.dt-frame-block code {
  padding: 1px 5px;
  background: var(--surface-alt, var(--surface));
  border-radius: 5px;
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 12px;
}

.dt-placeholder,
.dt-error {
  margin: 0;
  padding: 16px;
  color: var(--muted);
  font-size: 13.5px;
}

.dt-error {
  color: var(--rose, var(--ink));
  background: color-mix(in srgb, var(--rose, #e05260) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--rose, #e05260) 30%, transparent);
  border-radius: 9px;
}

.dt-foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 8px 20px;
  margin-top: 36px;
  padding-top: 18px;
  border-top: 1px solid var(--line-soft);
  color: var(--muted);
  font-size: 12.5px;
}

.dt-foot a { color: inherit; }

@media (max-width: 860px) {
  .dt-result-stats { grid-template-columns: minmax(0, 1fr); }
  .dt-block__head { flex-direction: column; align-items: flex-start; }
}

@media (prefers-reduced-motion: reduce) {
  .dt-device__check,
  .dt-switch,
  .dt-switch__box {
    transition: none;
  }
}

/* Frame actions sit under each preview: release the scroll, or open the site
   in its own tab. */
/* "Open at this size" — the escape hatch for sites that refuse framing. */
.dt-frame-sized {
  padding: 0;
  color: var(--dt-link, var(--blue-ink));
  cursor: pointer;
  background: none;
  border: 0;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
}

.dt-frame-sized:hover { text-decoration: underline; }

.dt-frame-sized:focus-visible {
  outline: 2px solid var(--aqua);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Reports the viewport the device window actually achieved, which is a
   measurement from popup.php rather than the size we asked for. */
.dt-frame-status {
  max-width: 34ch;
  margin: 0;
  color: var(--muted);
  font-size: 11.5px;
  line-height: 1.45;
}


/* Actions stack under the device details in the information column. */
.dt-frame-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
}

/* Below the breakpoint the information column would squeeze the viewport, so
   the row becomes a single column with the details above the frame. */
@media (max-width: 900px) {
  .dt-frame {
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
    padding: 16px;
  }

  .dt-frame-info {
    position: static;
  }

  .dt-frame-actions {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 14px;
  }
}

/* The blocked-frame panel leads with the way out, not the diagnosis. */
.dt-frame-block {
  align-items: flex-start;
  text-align: left;
}

.dt-frame-block__why {
  color: var(--muted);
  font-size: 12.5px;
}

.dt-frame-block__open {
  margin-top: 4px;
}

.dt-frame-block__hint {
  max-width: 44ch;
  color: var(--muted);
  font-size: 11.5px;
  line-height: 1.45;
}


/* Inline icons on the frame actions. They inherit colour and sit on the text
   baseline rather than floating above it. */
.dt-icon {
  flex: 0 0 auto;
  vertical-align: -2px;
}

.dt-frame-open,
.dt-frame-sized,
.dt-frame-release {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

/* The spec line is secondary to the device name above it. */
.dt-frame-spec,
.dt-frame-note {
  margin: 0;
}

/* Frame status line. A blocked pop-up is the one failure people actually hit
   with the sized window, so that case is a visible warning carrying the fix
   rather than another line of grey text. */
.dt-frame-status--warn {
  max-width: 62ch;
  padding: 9px 12px;
  color: var(--ink);
  background: color-mix(in srgb, var(--sun, #e0a800) 16%, transparent);
  border: 1px solid color-mix(in srgb, var(--sun, #e0a800) 45%, transparent);
  border-radius: 8px;
  font-weight: 500;
}

.dt-frame-status--ok {
  color: var(--dt-link, var(--blue-ink));
}

/* Server-rendered screenshot, shown in place of a frame the site refused to
   be embedded in. Sized to the device viewport like the iframe it replaces,
   so what is on screen is still the real width. */
.dt-frame-shot {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  background: #fff;
}

.dt-frame-block__shot {
  margin-top: 6px;
}

.dt-frame-block__open,
.dt-frame-block__shot {
  align-self: flex-start;
}


/* --- Test button ----------------------------------------------------------
   No colour override here on purpose.

   The theme's own rule is `.btn--primary { background: var(--aqua); color:
   var(--on-accent) }`, so the button follows whatever accent the palette
   picker has set, exactly like the checkboxes, section icons and links
   around it. An earlier version pinned it to --blue-deep for contrast, which
   made it the one control that ignored the picker — it stayed blue while the
   rest of the page turned rose.

   Contrast is handled by --on-accent, which the picker derives per colour:
   ink on light accents, white on dark ones. See js/palette.js.
   -------------------------------------------------------------------------- */

/* --- Address field --------------------------------------------------------
   The field is highlighted so the one thing the page needs from you is the
   most obvious thing in the bar.

   The tint is derived from --sun rather than a literal yellow, so it follows
   the theme instead of being a pale wash in day and a glare in night. Day
   mixes the accent into white and takes dark ink; night mixes a much smaller
   amount into the dark surface, because a light yellow behind night mode's
   pale text would be unreadable — the same tint value in both themes would
   have inverted the contrast rather than preserved it.
   -------------------------------------------------------------------------- */

.dt-url-form {
  /* The theme pins .topbar__search to `flex: 0 1 340px`, which was already
     tight and became unusable once the button read "Test Website" instead of
     "Test" — 154px left for a URL. This grows into the bar's free space and
     stops before it crowds the controls on the right. */
  flex: 1 1 440px;
  max-width: 620px;
  min-width: 0;
  padding: 4px 6px 4px 14px;
  background: color-mix(in srgb, var(--sun) 20%, #fffdf5);
  border: 1px solid color-mix(in srgb, var(--sun) 42%, transparent);
  border-radius: 999px;
  transition: border-color .18s var(--ease), box-shadow .18s var(--ease);
}

.dt-url-form:focus-within {
  border-color: color-mix(in srgb, var(--sun) 70%, transparent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--sun) 24%, transparent);
}

/* Day mode's field is pale, so its text and placeholder take the dark ink
   regardless of the theme's own foreground. */
.dt-url-form input[type="url"] {
  color: #2a2010;
}

.dt-url-form input[type="url"]::placeholder {
  color: #7d6a45;
  opacity: 1;
}

.dt-url-globe {
  flex: 0 0 auto;
  color: #9a7b3a;
}

/* --- Phone: the address field gets its own row ----------------------------
   shell.css lets the topbar wrap below 720px; this decides what lands where.
   The field needs the full width to be usable at all, and a high order value
   puts it on the second row without having to give an order to any of its
   siblings. The appearance switcher, palette and home link stay on the top
   row, pushed right by the spacer that is already there. */
@media (max-width: 720px) {
  .dt-url-form {
    order: 10;
    flex: 1 1 100%;
    max-width: none;
  }
}

/* Night: a warm, dark field. The same pale yellow would have put this theme's
   light text on a near-white ground. */
html[data-theme="night"] .dt-url-form {
  background: color-mix(in srgb, var(--sun) 13%, var(--surface));
  border-color: color-mix(in srgb, var(--sun) 34%, transparent);
}

html[data-theme="night"] .dt-url-form input[type="url"] {
  color: var(--ink);
}

html[data-theme="night"] .dt-url-form input[type="url"]::placeholder {
  color: color-mix(in srgb, var(--sun) 46%, var(--muted));
}

html[data-theme="night"] .dt-url-globe {
  color: color-mix(in srgb, var(--sun) 66%, var(--ink-soft));
}

/* The button sits inside the pill now, so it loses its own outer margin and
   keeps a little height back from the field's edge. */
.dt-test-btn {
  flex: 0 0 auto;
  gap: 7px;
  height: 36px;
  padding-inline: 16px;
}

@media (prefers-reduced-motion: reduce) {
  .dt-url-form { transition: none; }
}

/* ==========================================================================
   Sidebar toggle icons
   ========================================================================== */

/* --- Collapse: two chevrons running toward the rail ----------------------
   Replaces the half-filled circle, which read as an unrelated glyph rather
   than as "move this out of the way". Each chevron fades in, travels, and
   fades out; the second trails the first by half a cycle, so one is always
   mid-travel and the button never appears blank. */
.dt-collapse .dt-chev {
  animation: dt-chev-run 2.6s ease-in infinite;
}

.dt-collapse .dt-chev--b {
  animation-delay: 1.3s;
}

/* Hovering speeds the pair up, which reads as the control responding rather
   than simply continuing. */
.dt-collapse:hover .dt-chev {
  animation-duration: 1s;
}

.dt-collapse:hover .dt-chev--b {
  animation-delay: .5s;
}

@keyframes dt-chev-run {
  0%   { transform: translateX(2px);  opacity: 0; }
  40%  { opacity: 1; }
  100% { transform: translateX(-3px); opacity: 0; }
}

/* Collapsed, the rail reopens to the right, so the chevrons run that way and
   the icon mirrors. The arrow always points where the next click sends it. */
body.is-collapsed .dt-collapse svg {
  transform: scaleX(-1);
}

/* --- The boat -------------------------------------------------------------
   At rest it rocks on its waves; on hover it picks up and sails. The hull and
   the water animate independently, which is what stops it reading as one
   image wobbling — the boat rides the swell rather than moving with it.
   -------------------------------------------------------------------------- */

.dt-boat svg {
  overflow: visible;
}

/* --- "Devices" label, phone only ------------------------------------------
   On a phone the sidebar is a closed drawer and the boat is the only way to
   open it, which a lone icon does not communicate. This turns the icon button
   into a labelled pill below 720px.

   The tint is the same --sun recipe as the address field two elements away, so
   the bar reads as having one highlighted affordance rather than two competing
   ones, and it follows the theme instead of being a literal yellow that glares
   in night mode. Contrast is carried by the text colour, which is pinned to
   the same dark ink the address field uses on its own pale ground.

   Hidden on desktop: the sidebar is permanently on screen there, so there is
   nothing to invite. .icon-btn is a fixed 38px grid cell, hence the width,
   padding and flow reset here. */
.dt-boat__label {
  display: none;
}

@media (max-width: 720px) {
  .dt-boat {
    width: auto;
    height: 38px;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 0 13px 0 9px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--sun) 20%, #fffdf5);
    border: 1px solid color-mix(in srgb, var(--sun) 42%, transparent);
    color: #2a2010;
  }

  /* .icon-btn's hover fill would drop the tint back to the bar's grey. */
  .dt-boat:hover {
    background: color-mix(in srgb, var(--sun) 28%, #fffdf5);
    color: #2a2010;
  }

  .dt-boat__label {
    display: inline;
    font-size: var(--fs-sm);
    font-weight: var(--fw-semi, 600);
    letter-spacing: var(--track-snug);
    white-space: nowrap;
  }

  /* Night: a warm dark pill, for the same reason the address field has one —
     the pale ground would put light topbar text on near-white. */
  html[data-theme="night"] .dt-boat {
    background: color-mix(in srgb, var(--sun) 13%, var(--surface));
    border-color: color-mix(in srgb, var(--sun) 34%, transparent);
    color: var(--ink);
  }

  html[data-theme="night"] .dt-boat:hover {
    background: color-mix(in srgb, var(--sun) 20%, var(--surface));
    color: var(--ink);
  }
}

.dt-boat__hull {
  transform-origin: 12px 15px;
  animation: dt-boat-rock 3.4s ease-in-out infinite;
}

/* The two wave lines run at different speeds and phases so the water never
   pulses as a single block. */
.dt-boat__wave--a {
  animation: dt-wave-a 2.6s ease-in-out infinite;
}

.dt-boat__wave--b {
  animation: dt-wave-b 3.3s ease-in-out infinite;
}

@keyframes dt-boat-rock {
  0%, 100% { transform: rotate(-4.5deg) translateY(0); }
  50%      { transform: rotate(4.5deg)  translateY(-0.7px); }
}

@keyframes dt-wave-a {
  0%, 100% { transform: translateX(0); }
  50%      { transform: translateX(-3.2px); }
}

@keyframes dt-wave-b {
  0%, 100% { transform: translateX(-2.4px); }
  50%      { transform: translateX(0); }
}

/* Hover: the sea picks up and the boat leans into it. */
.dt-boat:hover .dt-boat__hull {
  animation-duration: 1.1s;
}

.dt-boat:hover .dt-boat__wave--a {
  animation-duration: .9s;
}

.dt-boat:hover .dt-boat__wave--b {
  animation-duration: 1.2s;
}

/* The sail fills out as it catches the wind. */
.dt-boat__sail {
  transform-origin: 12px 12px;
  transition: transform .3s var(--ease);
}

.dt-boat:hover .dt-boat__sail {
  transform: scaleX(1.16);
}

@media (prefers-reduced-motion: reduce) {
  .dt-collapse .dt-chev {
    animation: none;
    opacity: 1;
    transform: none;
  }

  /* The boat still sits on its water, it just stops moving. */
  .dt-boat__hull,
  .dt-boat__wave--a,
  .dt-boat__wave--b {
    animation: none;
    transform: none;
  }

  .dt-boat__sail {
    transition: none;
  }

  .dt-boat:hover .dt-boat__sail {
    transform: none;
  }
}
