/* ---------------------------------------------------------------- tokens
   Warm paper ground and hairline-bounded surfaces, following the house style.
   One saturated colour only: stamp-ink blue, spent on the create action, the
   result slab, the active filter and focus rings. Nothing else is coloured.
   Swap --accent (and --accent-ink for its dark-mode lift) to re-skin. */
:root {
  --paper:      #f4f2ea;
  --card:       #fdfdf9;
  --ink:        #1e212b;
  --ink-soft:   #6b6f7c;
  --ink-faint:  #9a9dab;
  --rule:       #e3e0d5;
  --rule-firm:  #d3cfc1;
  --accent:     #2440d9;
  --accent-ink: #ffffff;
  --accent-wash:#e7eafb;
  --bad:        #a32d1d;

  --radius: 8px;
  --radius-lg: 14px;
  --gutter: 20px;
  --sidebar: 232px;
  /* Starting value only. The top bar wraps at narrow widths, so its real
     height is measured and written back to this variable by the script. */
  --topbar-h: 59px;
  --sans: Inter, ui-sans-serif, -apple-system, "system-ui", "Segoe UI", sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
}

:root[data-theme="dark"],
:root[data-theme="dark"] * { color-scheme: dark; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper:      #15161a;
    --card:       #1d1f25;
    --ink:        #eceadf;
    --ink-soft:   #9b9fae;
    --ink-faint:  #6c7080;
    --rule:       #2c2f37;
    --rule-firm:  #3b3f49;
    --accent:     #5b78ff;
    --accent-ink: #0d1020;
    --accent-wash:#22273d;
    --bad:        #e8836f;
  }
}

:root[data-theme="dark"] {
  --paper:      #15161a;
  --card:       #1d1f25;
  --ink:        #eceadf;
  --ink-soft:   #9b9fae;
  --ink-faint:  #6c7080;
  --rule:       #2c2f37;
  --rule-firm:  #3b3f49;
  --accent:     #5b78ff;
  --accent-ink: #0d1020;
  --accent-wash:#22273d;
  --bad:        #e8836f;
}

*, *::before, *::after { box-sizing: border-box; }

/* The UA rule for [hidden] is a bare attribute selector, so any class that sets
   `display` outranks it. Every toggled element here sets one, so state the
   intent once rather than remembering to guard each rule. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* ------------------------------------------------------------------ shell
   Sidebar for navigation, a fixed top bar for search and the primary action,
   and a scrolling card grid -- the arrangement a link console wants, kept in
   the flat hairline idiom the rest of the family uses. */
.shell {
  display: grid;
  grid-template-columns: var(--sidebar) 1fr;
  min-height: 100vh;
}

.shell[data-sidebar="closed"] { grid-template-columns: 0 1fr; }
.shell[data-sidebar="closed"] .sidebar { display: none; }

.sidebar {
  display: flex;
  flex-direction: column;
  gap: 22px;
  padding: 20px 14px;
  border-right: 1px solid var(--rule);
  background: var(--card);
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.sidebar .mark { padding: 0 8px; }

.nav { flex: 1; }

.nav-heading {
  font-size: 12px;
  font-weight: 560;
  color: var(--ink-faint);
  margin: 18px 0 6px 8px;
}

.nav-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* A category entry is a path segment, drawn like every other address. */
.nav-name .addr-cat { font-family: var(--mono); font-size: 13px; color: inherit; }

.nav ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; }

.nav button {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
  font: inherit;
  font-size: 13.5px;
  color: var(--ink-soft);
  background: none;
  border: 0;
  border-radius: 6px;
  padding: 7px 8px;
  cursor: pointer;
  text-align: left;
}

.nav button:hover { background: var(--paper); color: var(--ink); }

.nav button[aria-current="true"] {
  background: var(--accent-wash);
  color: var(--accent);
  font-weight: 560;
}

.nav .count {
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  color: var(--ink-faint);
}

.nav button[aria-current="true"] .count { color: var(--accent); }

.sidebar-foot { display: grid; gap: 12px; }

.theme {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  width: fit-content;
}

.theme button {
  display: grid;
  place-items: center;
  width: 26px;
  height: 24px;
  color: var(--ink-faint);
  background: none;
  border: 0;
  border-radius: 5px;
  cursor: pointer;
}

.theme button svg { width: 14px; height: 14px; }
.theme button:hover { color: var(--ink); }
.theme button[aria-checked="true"] { color: var(--accent); background: var(--card); }

.session {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 0 4px;
}

/* ------------------------------------------------------------------ topbar */
.main { min-width: 0; display: flex; flex-direction: column; }

.topbar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px var(--gutter);
  border-bottom: 1px solid var(--rule);
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--paper);
}

.search {
  position: relative;
  flex: 0 1 360px;
  min-width: 0;
  margin-right: auto;
}

.search-icon {
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  width: 14px;
  height: 14px;
  color: var(--ink-faint);
  pointer-events: none;
}

.search input { padding-left: 31px; }
.search input::-webkit-search-cancel-button { appearance: none; }

.icon-button {
  display: grid;
  place-items: center;
  flex: none;
  width: 30px;
  height: 30px;
  color: var(--ink-soft);
  background: none;
  border: 0;
  border-radius: 6px;
  cursor: pointer;
}

.icon-button svg { width: 16px; height: 16px; }
.icon-button:hover { color: var(--accent); background: var(--accent-wash); }
.icon-button:disabled { opacity: 0.35; cursor: default; background: none; color: var(--ink-faint); }
.icon-button.is-done { color: var(--accent); background: var(--accent-wash); }

/* --------------------------------------------------------------- page head
   The only large type in the console. It names what is being browsed, and for
   a category, spells out the address every link in it begins with. */
.page-head { padding: 26px var(--gutter) 0; min-width: 0; }

.page-head h1 {
  margin: 0;
  font-size: 28px;
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 1.15;
  overflow-wrap: anywhere;
}

.page-prefix {
  margin: 6px 0 0;
  font-family: var(--mono);
  font-size: 13px;
  overflow-wrap: anywhere;
}

/* A back step shown only when looking at one link's analytics. */
.page-up {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  margin: 0 0 10px -5px;
  padding: 3px 8px 3px 3px;
  font-size: 13px;
  color: var(--ink-soft);
  text-decoration: none;
  border-radius: 6px;
}

.page-up svg { width: 15px; height: 15px; }
.page-up:hover { color: var(--accent); background: var(--accent-wash); }

/* One link's heading is its address, set like the cards set it. */
.page-head h1.is-address { font-family: var(--mono); font-weight: 500; font-size: 26px; letter-spacing: -0.025em; }

.page-prefix.is-destination { font-family: var(--sans); font-size: 13.5px; }
.page-prefix .dest { display: inline; margin: 0; white-space: normal; overflow-wrap: anywhere; }

/* Two views of the same scope. The rule under them ends the page head. */
.tabs {
  display: flex;
  gap: 24px;
  margin-top: 20px;
  border-bottom: 1px solid var(--rule);
}

.tab {
  position: relative;
  padding: 0 1px 11px;
  font-size: 14px;
  font-weight: 500;
  color: var(--ink-soft);
  text-decoration: none;
}

.tab:hover { color: var(--ink); }
.tab[aria-current="page"] { color: var(--ink); font-weight: 600; }

.tab[aria-current="page"]::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  border-radius: 2px 2px 0 0;
  background: var(--accent);
}

.tab:focus-visible { outline-offset: 4px; border-radius: 2px; }

/* ----------------------------------------------------------------- toolbar */
.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 16px var(--gutter) 14px;
}

.toolbar-end { display: flex; align-items: center; gap: 14px; }
.tally { color: var(--ink-faint); font-size: 13px; font-variant-numeric: tabular-nums; }
.toolbar-end .select { width: 160px; }

.mark {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.03em;
}

/* The favicon, at size: the one place the brand is drawn rather than written. */
.mark-tile {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 7px;
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: -0.06em;
}

.mark-large { font-size: 18px; gap: 11px; }
.mark-large .mark-tile { width: 40px; height: 40px; border-radius: 10px; font-size: 19px; }

.bar-end { display: flex; align-items: center; gap: 14px; }

.scope { color: var(--ink-soft); font-size: 13px; }

/* ----------------------------------------------------------------- unlock */
.unlock {
  max-width: 440px;
  margin: 0 auto;
  padding: 16vh var(--gutter) 0;
}

.unlock .mark { display: flex; margin-bottom: 40px; }

.unlock h1 {
  font-size: 32px;
  font-weight: 600;
  letter-spacing: -0.04em;
  line-height: 1.1;
  margin: 0;
}

.unlock .lede { color: var(--ink-soft); margin: 12px 0 22px; max-width: 38em; }

#unlock-form { display: flex; gap: 8px; }
#unlock-form input { flex: 1; }

/* ----------------------------------------------------------------- inputs */
input, select {
  width: 100%;
  font: inherit;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--rule-firm);
  border-radius: var(--radius);
  padding: 9px 11px;
  transition: border-color 120ms ease;
}

input::placeholder { color: var(--ink-faint); }

input:hover, select:hover { border-color: var(--ink-faint); }

input:focus-visible, select:focus-visible,
button:focus-visible, a:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

#url-input, #id-input, #category-input { font-family: var(--mono); font-size: 13px; }

label, .label {
  display: block;
  font-size: 13px;
  color: var(--ink-soft);
  margin-bottom: 5px;
}

.hint {
  font-size: 12.5px;
  color: var(--ink-faint);
  margin: 6px 0 0;
}

/* ---------------------------------------------------------------- buttons */
.accent-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  font: inherit;
  white-space: nowrap;
  font-weight: 620;
  font-size: 13px;
  color: var(--accent-ink);
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  padding: 10px 20px;
  cursor: pointer;
}

.accent-button svg { width: 14px; height: 14px; flex: none; margin-left: -3px; }
.accent-button:hover { filter: brightness(1.12); }
.accent-button:disabled { opacity: 0.45; cursor: default; filter: none; }

.quiet-button {
  font: inherit;
  font-size: 13px;
  color: var(--ink-soft);
  background: none;
  border: 0;
  border-radius: 6px;
  padding: 3px 7px;
  cursor: pointer;
}

.quiet-button:hover { color: var(--accent); background: var(--accent-wash); }
.quiet-button.danger:hover { color: var(--bad); background: none; }
.quiet-button-framed {
  border: 1px solid var(--rule-firm);
  border-radius: var(--radius);
  padding: 8px 14px;
  color: var(--ink);
}

.quiet-button:disabled { opacity: 0.4; cursor: default; background: none; color: var(--ink-faint); }

/* --------------------------------------------------------- floating layers
   Cards elsewhere are flat and bounded by a hairline. A menu has to read as
   *above* the page rather than part of it, so these are the one place that
   carries elevation -- kept to a whisper, and paired with a firmer border. */
.combo, .select { position: relative; }

.menu {
  position: absolute;
  z-index: 20;
  top: calc(100% + 5px);
  left: 0;
  right: 0;
  margin: 0;
  padding: 5px;
  list-style: none;
  max-height: 260px;
  overflow-y: auto;
  background: var(--card);
  border: 1px solid var(--rule-firm);
  border-radius: var(--radius);
  box-shadow: 0 6px 20px -8px rgba(20, 22, 30, 0.28);
  animation: menu-in 110ms ease-out;
}

@keyframes menu-in {
  from { opacity: 0; transform: translateY(-3px); }
  to   { opacity: 1; transform: none; }
}

.menu li {
  padding: 7px 10px;
  border-radius: 5px;
  font-size: 13px;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.menu li[aria-selected="true"] { color: var(--accent); font-weight: 560; }

/* One highlight, driven by keyboard and pointer alike, so arrowing and
   hovering never disagree about which row is active. */
.menu li.is-active { background: var(--accent-wash); color: var(--accent); }

.menu li.is-empty {
  color: var(--ink-faint);
  cursor: default;
  background: none;
  font-style: normal;
}

/* ------------------------------------------------------------ select button */
.select-button {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
  font: inherit;
  font-size: 14px;
  text-align: left;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--rule-firm);
  border-radius: var(--radius);
  padding: 9px 11px;
  cursor: pointer;
  transition: border-color 120ms ease;
}

.select-button:hover { border-color: var(--ink-faint); }
.select[data-open="true"] .select-button { border-color: var(--accent); }

.caret {
  width: 12px;
  height: 12px;
  flex: none;
  color: var(--ink-faint);
  transition: transform 140ms ease;
}

.select[data-open="true"] .caret { transform: rotate(180deg); }

/* -------------------------------------------------------- segmented control */
.segmented {
  display: inline-flex;
  padding: 3px;
  gap: 3px;
  background: var(--paper);
  border: 1px solid var(--rule-firm);
  border-radius: var(--radius);
}

.segmented button {
  font: inherit;
  font-size: 13px;
  color: var(--ink-soft);
  background: none;
  border: 0;
  border-radius: 5px;
  padding: 6px 14px;
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.segmented button:hover { color: var(--ink); }

.segmented button[aria-checked="true"] {
  color: var(--accent-ink);
  background: var(--accent);
}

/* ------------------------------------------------------------ create card */
.create {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius-lg);
  padding: 20px;
}

.field-wide { grid-column: 1 / -1; }

.create-end {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 14px;
  flex-wrap: wrap;
}

.create-end .notice { margin: 0; margin-right: auto; }

/* ------------------------------------------------------------- result slab
   The one loud moment in the page: a freshly minted link lands full width in
   accent ink, the address set large in mono so every character of the ending
   is unambiguous. Everything else on the page stays quiet so this can shout. */
.slab {
  position: relative;
  display: flex;
  align-items: center;
  gap: 20px;
  margin: 0 var(--gutter) 16px;
  padding: 18px 56px 18px 22px;
  background: var(--accent);
  color: var(--accent-ink);
  border-radius: var(--radius-lg);
}

.slab-enter { animation: slab-in 280ms cubic-bezier(0.2, 0.8, 0.3, 1); }

@keyframes slab-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: none; }
}

.slab-text { flex: 1; min-width: 0; }
.slab-text p { margin: 0; }

.slab-title { font-size: 13px; font-weight: 600; opacity: 0.8; }

.slab-url {
  font-family: var(--mono);
  font-size: 22px;
  line-height: 1.3;
  letter-spacing: -0.02em;
  margin: 2px 0 4px !important;
  overflow-wrap: anywhere;
}

/* On accent the usual receding greys would vanish, so the prefix recedes by
   opacity instead, and the ending takes the weight. */
.slab-url .addr-host,
.slab-url .addr-cat { color: inherit; opacity: 0.62; }
.slab-url .addr-id { color: inherit; font-weight: 600; }

.slab-posture { font-size: 12.5px; opacity: 0.78; }

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

.slab-button {
  font: inherit;
  font-weight: 600;
  font-size: 13px;
  color: var(--accent-ink);
  background: none;
  border: 1px solid color-mix(in srgb, currentColor 55%, transparent);
  border-radius: var(--radius);
  padding: 8px 14px;
  cursor: pointer;
  white-space: nowrap;
}

.slab-button:hover { background: color-mix(in srgb, currentColor 14%, transparent); }

/* The copy action is the reason the banner exists, so it is the solid one. */
.slab-button-solid { background: var(--accent-ink); color: var(--accent); border-color: var(--accent-ink); }
.slab-button-solid:hover { background: var(--accent-ink); filter: brightness(0.94); }

.slab .slab-button:focus-visible,
.slab .slab-close:focus-visible { outline-color: var(--accent-ink); }

.slab-close {
  position: absolute;
  top: 10px;
  right: 10px;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  color: inherit;
  opacity: 0.7;
  background: none;
  border: 0;
  border-radius: 6px;
  cursor: pointer;
}

.slab-close svg { width: 14px; height: 14px; }
.slab-close:hover { opacity: 1; background: color-mix(in srgb, currentColor 14%, transparent); }

/* ------------------------------------------------------------- addresses
   Shared by every place a short link is drawn: the prefix recedes, the ending
   carries the ink. */
.addr-host, .addr-cat { color: var(--ink-faint); }
.addr-id { color: var(--ink); }

/* -------------------------------------------------------------- card grid
   Flat, hairline-bounded cards. No shadow: elevation in this family is
   reserved for things that genuinely float, which is menus and dialogs.
   Each card reads top to bottom as address, what it is, where it goes, and
   its state -- with the state on a rule of its own. */
.grid {
  list-style: none;
  margin: 0;
  padding: 0 var(--gutter) 64px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 12px;
}

/* An empty grid would otherwise keep its bottom padding above the empty state. */
.grid:empty { display: none; }

.card {
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: 14px 16px 0;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius-lg);
  transition: border-color 120ms ease;
}

.card:hover { border-color: var(--rule-firm); }

.card-head { display: flex; align-items: center; gap: 8px; min-width: 0; margin: -3px 0 0; }

.short {
  display: inline-flex;
  align-items: center;
  font-family: var(--mono);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.015em;
  color: var(--ink);
  text-decoration: none;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
}

.short .addr-id { overflow: hidden; text-overflow: ellipsis; }

a.short:hover .addr-id { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }

/* A protected link cannot be opened by clicking it, so it is text, not a
   link -- and the lock says why. */
.short-plain { cursor: default; }
.lock { width: 12px; height: 12px; flex: none; margin-right: 6px; color: var(--ink-faint); }

.card-actions { display: flex; align-items: center; gap: 1px; margin-left: auto; margin-right: -6px; flex: none; }

.card-note {
  margin: 6px 0 0;
  font-size: 14px;
  line-height: 1.4;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.dest {
  display: block;
  margin: 4px 0 14px;
  font-size: 13px;
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dest-host { color: var(--ink-soft); }
.dest-path { color: var(--ink-faint); }
.dest:hover .dest-host, .dest:hover .dest-path { color: var(--ink); }
.dest:hover { text-decoration: underline; text-decoration-color: var(--rule-firm); text-underline-offset: 3px; }

/* The state row sits on its own rule at the foot, and is pushed there by
   margin-top: auto so the rules line up across a row of unequal cards. */
.card-foot {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: auto -16px 0;
  padding: 9px 16px 10px;
  border-top: 1px solid var(--rule);
  min-height: 40px;
}

.card-tags { display: flex; align-items: center; gap: 6px 12px; flex-wrap: wrap; min-width: 0; }

.tag {
  font-size: 12px;
  color: var(--ink-soft);
  white-space: nowrap;
}

.tag-clicks { font-variant-numeric: tabular-nums; }
.tag-off { color: var(--bad); font-weight: 560; }

.card-date {
  margin-left: auto;
  flex: none;
  font-size: 12px;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

/* Protected is the default, so only the exception gets the accent. */
.pill {
  flex: none;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--accent);
  background: var(--accent-wash);
  border-radius: 999px;
  padding: 2px 9px;
}

/* A disabled or expired link is shown by taking presence away. */
.card.is-off .addr-id { text-decoration: line-through; color: var(--ink-faint); }
.card.is-off .card-note,
.card.is-off .dest-host { color: var(--ink-faint); }

.card-confirm {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  font-size: 13px;
  color: var(--ink);
  margin: 0 -16px;
  padding: 9px 16px 10px;
  border-top: 1px solid var(--rule);
  background: color-mix(in srgb, var(--bad) 7%, var(--card));
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

.card-confirm span { margin-right: auto; }

/* The confirm row replaces the state row rather than stacking under it. */
.card:has(.card-confirm:not([hidden])) .card-foot { display: none; }

.quiet-button.danger { color: var(--bad); font-weight: 600; }

/* -------------------------------------------------------- modal additions */
.field-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 5px;
}

.field-head label { margin-bottom: 0; }
.field-head .icon-button { width: 24px; height: 24px; margin: -3px -4px -3px 0; }
.field-head .icon-button svg { width: 13px; height: 13px; }

/* ------------------------------------------------------------ range slider
   Range inputs are one of the few native controls that can be styled all the
   way through, so this one is built rather than replaced. */
.length-value {
  font-family: var(--mono);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
}

input[type="range"] {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  height: 20px;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
}

input[type="range"]::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 999px;
  background: var(--rule-firm);
}

input[type="range"]::-moz-range-track {
  height: 4px;
  border-radius: 999px;
  background: var(--rule-firm);
}

input[type="range"]::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  width: 15px;
  height: 15px;
  margin-top: -5.5px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--card);
  box-shadow: 0 0 0 1px var(--accent);
}

input[type="range"]::-moz-range-thumb {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--card);
  box-shadow: 0 0 0 1px var(--accent);
}

input[type="range"]:disabled { cursor: not-allowed; opacity: 0.45; }
input[type="range"]:disabled::-webkit-slider-thumb { background: var(--ink-faint); box-shadow: 0 0 0 1px var(--ink-faint); }
input[type="range"]:disabled::-moz-range-thumb { background: var(--ink-faint); box-shadow: 0 0 0 1px var(--ink-faint); }

input[type="range"]:focus-visible { outline: none; }
input[type="range"]:focus-visible::-webkit-slider-thumb { outline: 2px solid var(--accent); outline-offset: 2px; }
input[type="range"]:focus-visible::-moz-range-thumb { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The hint under the slider is guidance, not a field caption. */
#length-hint { margin-top: 2px; }

/* The finished link, shown while the form is still being filled. Quiet enough
   to read as a readout rather than an input. */
.preview {
  display: block;
  font-family: var(--mono);
  font-size: 15px;
  letter-spacing: -0.015em;
  background: var(--accent-wash);
  border: 1px solid transparent;
  border-radius: var(--radius);
  padding: 10px 12px;
  overflow-wrap: anywhere;
}

.preview .addr-host, .preview .addr-cat { color: color-mix(in srgb, var(--accent) 62%, var(--card)); }
.preview .addr-id { color: var(--accent); font-weight: 600; }

.preview.is-waiting { background: var(--paper); }
.preview.is-waiting .addr-host,
.preview.is-waiting .addr-cat,
.preview.is-waiting .addr-id { color: var(--ink-faint); font-weight: 400; }

.preview-aside { font-family: var(--sans); font-size: 12.5px; color: var(--ink-faint); margin-left: 10px; }

/* A locked field still shows its value; it just cannot be the thing you change. */
input:disabled {
  color: var(--ink-faint);
  background: var(--paper);
  cursor: not-allowed;
}

/* ------------------------------------------------------------------- modal */
.modal {
  width: min(560px, calc(100vw - 32px));
  max-height: calc(100vh - 64px);
  padding: 0;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--rule-firm);
  border-radius: var(--radius-lg);
  box-shadow: 0 24px 60px -24px rgba(16, 18, 26, 0.45);
}

.modal::backdrop { background: rgba(18, 20, 28, 0.42); backdrop-filter: blur(2px); }

.modal form { display: flex; flex-direction: column; max-height: inherit; }

.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 18px 20px 14px;
  border-bottom: 1px solid var(--rule);
}

.modal-head h2 {
  margin: 0;
  font-size: 17px;
  font-weight: 560;
  letter-spacing: -0.02em;
}

.modal-body {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  padding: 18px 20px;
  overflow-y: auto;
}

.modal-foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  padding: 14px 20px 18px;
  border-top: 1px solid var(--rule);
}

.modal-foot .notice { margin: 0; margin-right: auto; }

/* --------------------------------------------------------------- qr dialog */
.modal-qr { width: min(360px, calc(100vw - 32px)); }

.qr-body {
  display: grid;
  justify-items: center;
  gap: 12px;
  padding: 22px 20px 6px;
}

/* White behind the code regardless of theme: scanners want the real contrast,
   and a dark-mode QR on a dark card reads poorly on many phones. */
.qr-frame {
  background: #ffffff;
  border: 1px solid var(--rule-firm);
  border-radius: var(--radius);
  padding: 10px;
  line-height: 0;
}

.qr-frame svg { display: block; width: 232px; height: 232px; }

.qr-url {
  font-family: var(--mono);
  font-size: 14px;
  color: var(--ink);
  margin: 0;
  text-align: center;
  overflow-wrap: anywhere;
}

.qr-body .hint { text-align: center; margin: 0; }

/* The overflow trigger borrows .select-button for its behaviour, not its looks. */
.overflow .select-button {
  width: 30px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-soft);
  justify-content: center;
}

.overflow .select-button:hover,
.overflow[data-open="true"] .select-button { color: var(--accent); background: var(--accent-wash); }

/* Overflow menus hang off the right edge of their button, not the full width. */
.menu-right { left: auto; right: 0; min-width: 168px; }

.menu li[role="menuitem"] { color: var(--ink-soft); }
.menu li[role="menuitem"]:hover, .menu li.is-active { color: var(--accent); background: var(--accent-wash); }
.menu li.is-danger:hover { color: var(--bad); background: none; }

/* --------------------------------------------------------------- messages */
.notice {
  font-size: 13px;
  color: var(--ink-soft);
  margin: 0 var(--gutter) 10px;
}

/* Informational, not an error: a hairline strip that sits above the grid and
   out of the way. */
#stats-note, #readonly-note, #demo-note {
  font-size: 12.5px;
  color: var(--ink-soft);
  margin: 0 var(--gutter) 14px;
  padding: 8px 12px;
  border: 1px dashed var(--rule-firm);
  border-radius: var(--radius);
}

.notice-bad { color: var(--bad); }

.empty {
  display: grid;
  justify-items: center;
  gap: 14px;
  margin: 0 var(--gutter) 64px;
  padding: 56px 20px;
  text-align: center;
  border: 1px dashed var(--rule-firm);
  border-radius: var(--radius-lg);
}

.empty-text { margin: 0; color: var(--ink-soft); font-size: 14px; }

/* ---------------------------------------------------------------- analytics
   The same flat panels as the link cards. Every chart shows one series, so
   every mark is the accent: a second hue would only restate what length or
   position already says. Axes and grids are hairlines one step off the
   surface, and text never takes the data colour. */
.analytics {
  display: grid;
  gap: 12px;
  padding: 0 var(--gutter) 64px;
  transition: opacity 160ms ease;
}

/* A refetch holds the previous picture, dimmed, rather than flashing empty. */
.analytics.is-loading { opacity: 0.55; pointer-events: none; }

.analytics-loading { color: var(--ink-faint); font-size: 13px; padding: 24px 0; }

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* Headline figures: one band, split by hairlines. Only the click count is
   large; the rest support it. Proportional figures, since none align. */
.kpis {
  display: grid;
  grid-template-columns: 1.7fr repeat(3, minmax(0, 1fr));
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius-lg);
}

.kpi { min-width: 0; padding: 18px 20px 20px; border-left: 1px solid var(--rule); }
.kpi:first-child { border-left: 0; }
.kpi p { margin: 0; }

.kpi-label { font-size: 13px; color: var(--ink-soft); }

.kpi-value {
  margin-top: 8px !important;
  font-size: 26px;
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.1;
  overflow-wrap: anywhere;
}

.kpi-hero .kpi-value { font-size: 54px; letter-spacing: -0.05em; line-height: 1; }

.kpi-detail { margin-top: 7px !important; font-size: 12.5px; color: var(--ink-faint); }
.kpi-hero .kpi-detail { color: var(--ink-soft); font-size: 13px; }

.panel {
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius-lg);
}

.panel-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 14px 16px 6px;
  min-width: 0;
}

.panel-title { margin: 0; font-size: 14.5px; font-weight: 600; letter-spacing: -0.015em; white-space: nowrap; }
.panel-aside { min-width: 0; font-size: 12.5px; color: var(--ink-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.panel-toggle {
  margin-left: auto;
  flex: none;
  font: inherit;
  font-size: 12.5px;
  color: var(--ink-soft);
  background: none;
  border: 1px solid var(--rule);
  border-radius: 6px;
  padding: 3px 9px;
  cursor: pointer;
}

.panel-toggle:hover { color: var(--accent); border-color: var(--rule-firm); }

.panel-table { max-height: 340px; overflow: auto; margin: 4px 16px 14px; }
.panel-empty { margin: 0; padding: 14px 16px 22px; font-size: 13px; color: var(--ink-faint); }

.panel-grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 12px;
}

.span-3 { grid-column: span 3; }
.span-4 { grid-column: span 4; }
.span-5 { grid-column: span 5; }
.span-6 { grid-column: span 6; }
.span-7 { grid-column: span 7; }
.span-12 { grid-column: 1 / -1; }

/* ------------------------------------------------------------ column chart */
.columns {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-rows: 210px auto;
  column-gap: 10px;
  padding: 22px 18px 14px 14px;
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

.columns:focus-visible, .heat:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.columns-y { position: relative; min-width: 2ch; }

.columns-tick {
  position: absolute;
  right: 0;
  transform: translateY(50%);
  font-size: 11.5px;
  line-height: 1;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

.columns-plot { position: relative; }
.columns-grid, .columns-bars { position: absolute; inset: 0; }

.columns-line {
  position: absolute;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--rule);
  transform: translateY(50%);
}

.columns-line.is-base { background: var(--rule-firm); }

.columns-bars { display: flex; }

/* The whole slot is the hover target; the bar inside is capped at 24px and
   leaves at least 2px of surface between neighbours. */
.col {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  justify-content: center;
  align-items: flex-end;
}

.col.is-active::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--accent-wash);
  opacity: 0.7;
  border-radius: 4px 4px 0 0;
}

.col-bar {
  position: relative;
  width: min(24px, calc(100% - 2px));
  background: var(--accent);
  border-radius: 4px 4px 0 0;
}

.col-bar.has-value { min-height: 2px; }
.is-dense .col-bar, .is-dense .col.is-active::before { border-radius: 1.5px 1.5px 0 0; }

/* A day still in progress, or cut by the window's start, is paler. */
.col-bar.is-partial { opacity: 0.42; }
.col.is-active .col-bar { filter: brightness(1.18); }

.col-peak {
  position: absolute;
  left: 50%;
  transform: translate(-50%, -5px);
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1;
  color: var(--ink-soft);
  white-space: nowrap;
  pointer-events: none;
}

.columns-x { display: flex; margin-top: 9px; grid-column: 2; }

.columns-x-label {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  justify-content: center;
  font-size: 11.5px;
  color: var(--ink-faint);
  white-space: nowrap;
}

/* Today's label would hang past the plot if centred under a thin last bar. */
.columns-x-label:last-child { justify-content: flex-end; }

/* ------------------------------------------------------------- ranked list */
.ranked {
  list-style: none;
  margin: 0;
  padding: 2px 8px 10px;
  display: grid;
  gap: 2px;
}

.ranked-row {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto 3.4em;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 32px;
  padding: 0 8px;
  font: inherit;
  font-size: 13px;
  color: var(--ink);
  text-align: left;
  background: none;
  border: 0;
  border-radius: 6px;
}

button.ranked-row { cursor: pointer; }
button.ranked-row:hover { background: var(--paper); }

/* A wash, not a block: the row's text sits on it and must stay legible. The
   data end is rounded, the baseline end square. */
.ranked-bar {
  position: absolute;
  left: 0;
  top: 3px;
  bottom: 3px;
  border-radius: 0 4px 4px 0;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  pointer-events: none;
}

button.ranked-row:hover .ranked-bar { background: color-mix(in srgb, var(--accent) 24%, transparent); }

.ranked-label, .ranked-value, .ranked-share { position: relative; }
.ranked-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ranked-value { font-weight: 600; font-variant-numeric: tabular-nums; }
.ranked-share { text-align: right; font-size: 12px; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.ranked-muted { color: var(--ink-soft); }

.ranked-link { display: flex; align-items: baseline; gap: 10px; min-width: 0; }
.ranked-address { font-family: var(--mono); font-size: 13px; flex: none; }
.ranked-sub { min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--ink-faint); font-size: 12.5px; }

.ranked-country { display: inline-flex; align-items: center; gap: 8px; }
.ranked-flag { font-size: 15px; line-height: 1; }

/* ----------------------------------------------------------------- heatmap
   One hue, more is darker, in five steps. An empty hour is an outline, not
   the lightest fill, so "none" never reads as "a few". */
.heat { padding: 8px 18px 16px; border-radius: 0 0 var(--radius-lg) var(--radius-lg); }

.heat-grid {
  display: grid;
  grid-template-columns: max-content repeat(24, minmax(0, 1fr));
  gap: 3px;
  align-items: center;
}

.heat-hour { font-size: 11px; color: var(--ink-faint); white-space: nowrap; overflow: visible; padding-bottom: 2px; }
.heat-day { font-size: 12px; color: var(--ink-soft); padding-right: 8px; }

.heat-cell { display: block; height: 22px; border-radius: 3px; }
.heat-cell.level-0 { box-shadow: inset 0 0 0 1px var(--rule); }
.heat-cell.level-1 { background: color-mix(in srgb, var(--accent) 14%, var(--card)); }
.heat-cell.level-2 { background: color-mix(in srgb, var(--accent) 32%, var(--card)); }
.heat-cell.level-3 { background: color-mix(in srgb, var(--accent) 52%, var(--card)); }
.heat-cell.level-4 { background: color-mix(in srgb, var(--accent) 74%, var(--card)); }
.heat-cell.level-5 { background: var(--accent); }
.heat-cell.is-active { outline: 2px solid var(--ink); outline-offset: 1px; }

.heat-legend {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 3px;
  margin-top: 14px;
  font-size: 11.5px;
  color: var(--ink-faint);
}

.heat-legend span:first-child { margin-right: 5px; }
.heat-legend span:last-child { margin-left: 5px; }
.heat-legend .heat-cell { width: 16px; height: 11px; }

/* --------------------------------------------------------------- tooltips
   Inverse ink so it reads in either theme; it floats, so it may carry the
   same whisper of elevation the menus do. */
.chart-tip {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 100;
  display: grid;
  gap: 1px;
  padding: 7px 10px;
  font-size: 12px;
  white-space: nowrap;
  color: var(--paper);
  background: var(--ink);
  border-radius: 6px;
  box-shadow: 0 6px 20px -8px rgba(20, 22, 30, 0.35);
  pointer-events: none;
}

.chart-tip-value { font-size: 13.5px; font-weight: 600; }
.chart-tip-label { opacity: 0.72; }

/* ------------------------------------------------------------ table twins */
.data-table { width: 100%; border-collapse: collapse; font-size: 13px; font-variant-numeric: tabular-nums; }

.data-table th {
  position: sticky;
  top: 0;
  padding: 6px 8px;
  text-align: left;
  font-weight: 560;
  color: var(--ink-soft);
  background: var(--card);
  border-bottom: 1px solid var(--rule-firm);
}

.data-table td { padding: 5px 8px; border-bottom: 1px solid var(--rule); white-space: nowrap; }
.data-table th:not(:first-child), .data-table td:not(:first-child) { text-align: right; }

/* ---------------------------------------------------- analytics switched off */
.empty-title { margin: 0; font-size: 16px; font-weight: 600; letter-spacing: -0.02em; color: var(--ink); }
.analytics-off .empty-text { max-width: 56ch; line-height: 1.55; }
.analytics-off .hint { max-width: 64ch; }
.analytics-off { margin: 0; }

/* The click count on a card is a way in to that link's analytics. */
button.tag-clicks {
  font: inherit;
  font-size: 12px;
  color: var(--ink-soft);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: var(--rule-firm);
  text-underline-offset: 3px;
}

button.tag-clicks:hover { color: var(--accent); text-decoration-color: currentColor; }

@media (max-width: 1200px) {
  .span-3 { grid-column: span 6; }
}

@media (max-width: 1000px) {
  .span-4, .span-5, .span-7 { grid-column: span 6; }
  .kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .kpi-hero { grid-column: 1 / -1; border-bottom: 1px solid var(--rule); }
  .kpi:nth-child(2) { border-left: 0; }
}

@media (max-width: 700px) {
  .panel-grid > * { grid-column: 1 / -1; }
  .kpi { padding: 14px 12px 16px; }
  .kpi-hero { padding: 16px 16px 18px; }
  .kpi-value { font-size: 20px; }
  .kpi-detail { font-size: 12px; }
  .kpi-hero .kpi-value { font-size: 46px; }
  .columns { grid-template-rows: 170px auto; padding-right: 12px; }
  .heat { padding: 8px 12px 14px; }
  .heat-grid { gap: 2px; }
  .heat-cell { height: 16px; border-radius: 2px; }
  .heat-hour { font-size: 10px; }
}

/* ----------------------------------------------------------------- mobile */
.scrim {
  position: fixed;
  inset: var(--topbar-h) 0 0 0;
  z-index: 35;
  background: rgba(18, 20, 28, 0.42);
}

@media (min-width: 861px) {
  /* The scrim belongs to the floating sidebar only; at this width it is inline. */
  .scrim { display: none !important; }
}

@media (max-width: 860px) {
  .shell,
  .shell[data-sidebar="closed"],
  .shell[data-sidebar="open"] { grid-template-columns: 1fr; }

  /* The sidebar slides in *below* the top bar rather than over it: its own
     toggle lives up there, and a panel that covers the control that dismisses
     it is a trap. */
  .topbar { z-index: 50; }

  .sidebar {
    position: fixed;
    top: var(--topbar-h);
    left: 0;
    bottom: 0;
    z-index: 40;
    width: var(--sidebar);
    height: auto;
    border-right: 1px solid var(--rule-firm);
  }

  /* The top bar already identifies the app at this width. */
  .sidebar > .mark { display: none; }

  .shell[data-sidebar="closed"] .sidebar { display: none; }
  .modal-body { grid-template-columns: 1fr; }
}

@media (max-width: 640px) {
  /* The search box yields space so the primary action stays on one line. */
  .search { flex: 1 1 auto; min-width: 90px; }
  .topbar .accent-button { padding: 10px 12px; }
  .topbar .accent-button span { display: none; }
  .topbar .accent-button svg { margin: 0; }
  .page-head { padding-top: 20px; }
  .page-head h1 { font-size: 24px; }
  .slab { flex-direction: column; align-items: stretch; gap: 14px; padding: 16px 44px 16px 16px; }
  .slab-url { font-size: 18px; }
  .slab-actions > * { flex: 1; }
  .grid { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}
