/* PLens. The app shell, in D4's vocabulary (design/directions/d4.html):
   tokens, a rail, an inner stage, and panes that switch in place.

   Two things differ from the preview sheet the vocabulary came from. The frame
   is the viewport here, not a boxed stage, so the breakpoints are media queries
   rather than container queries. And no webfont is fetched: both families are
   local names with a system fallback behind them. */

:root {
  --canvas: #F8F8F1;
  --ink: #1C385F;
  --ink-muted: rgba(28, 56, 95, .76);
  --ink-faint: rgba(28, 56, 95, .70);
  --surface: #FFFFFF;
  --edge: rgba(28, 56, 95, .12);
  --edge-strong: rgba(28, 56, 95, .22);
  --card: rgba(255, 255, 255, .66);
  --chip: rgba(255, 255, 255, .72);
  --chip-hover: rgba(255, 255, 255, .98);
  --row-hover: rgba(255, 255, 255, .60);
  --marker: rgba(28, 56, 95, .07);
  --green: #226B42;
  --verify-word: #8F5E0F;

  /* The energy scale is the register's own colour, carried by the data chip
     alone. Navigation stays navy. The D and E tint sits at .10, not .13: at
     .13 the amber letter on it measures 4.42:1, under AA. */
  --epc-ac: #2E6B4F;  --epc-ac-bg: rgba(46, 107, 79, .13);
  --epc-de: #8F5E0F;  --epc-de-bg: rgba(143, 94, 15, .10);
  --epc-fg: #8A2F2B;  --epc-fg-bg: rgba(138, 47, 43, .12);

  /* THE ONE FIELD: dark in both themes, so its ink stays fixed. */
  --field: #0F2138;
  --field-ink: #FFFFFF;
  --field-soft: rgba(255, 255, 255, .70);
  --field-door: rgba(255, 255, 255, .10);
  --field-door-hover: rgba(255, 255, 255, .18);
  --verify: #D9BA85;

  --action: #1C385F;
  --action-ink: #F8F8F1;
  --action-ring: transparent;

  --lift: 0 1px 2px rgba(28, 56, 95, .07), 0 10px 26px rgba(28, 56, 95, .09);
  --lift-sm: 0 1px 2px rgba(28, 56, 95, .10);

  --r-lg: 16px;
  --r-md: 14px;
  --r-sm: 10px;

  /* the ruled motion law: spring shaped easing, 150 to 300ms. linse.js reads
     this same value off the root, so the curve is written once. */
  --spring: linear(0,.006,.025 2.8%,.101 6.1%,.539 18.9%,.721 25.3%,.849 31.5%,.937 38.1%,.968 41.8%,.991 45.7%,1.006 50.1%,1.015 55%,1.017 63.9%,1.001);

  --sans: "Manrope", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* Dark is first-class: the system asks for it, and data-theme can overrule the
   system either way (the override wins on specificity). */
@media (prefers-color-scheme: dark) {
  :root {
    --canvas: #0d1520;
    --ink: #E9EFF7;
    --ink-muted: rgba(233, 239, 247, .62);
    --ink-faint: rgba(233, 239, 247, .55);
    --surface: #131e2c;
    --edge: rgba(233, 239, 247, .13);
    --edge-strong: rgba(233, 239, 247, .22);
    --card: rgba(255, 255, 255, .07);
    --chip: rgba(255, 255, 255, .07);
    --chip-hover: rgba(255, 255, 255, .13);
    --row-hover: rgba(255, 255, 255, .06);
    --marker: rgba(255, 255, 255, .08);
    --green: #6FBF8E;
    --verify-word: #D9BA85;
    --epc-ac: #6FBF92;  --epc-ac-bg: rgba(111, 191, 146, .15);
    --epc-de: #D9BA85;  --epc-de-bg: rgba(217, 186, 133, .15);
    --epc-fg: #E08F88;  --epc-fg-bg: rgba(224, 143, 136, .15);
    --field: #050c15;
    --action: #050c15;
    --action-ink: #E9EFF7;
    --action-ring: rgba(233, 239, 247, .42);
    --lift: 0 1px 2px rgba(0, 0, 0, .45), 0 12px 30px rgba(0, 0, 0, .40);
    --lift-sm: 0 1px 2px rgba(0, 0, 0, .45);
  }
}

:root[data-theme="light"] {
  --canvas: #F8F8F1;
  --ink: #1C385F;
  --ink-muted: rgba(28, 56, 95, .76);
  --ink-faint: rgba(28, 56, 95, .70);
  --surface: #FFFFFF;
  --edge: rgba(28, 56, 95, .12);
  --edge-strong: rgba(28, 56, 95, .22);
  --card: rgba(255, 255, 255, .66);
  --chip: rgba(255, 255, 255, .72);
  --chip-hover: rgba(255, 255, 255, .98);
  --row-hover: rgba(255, 255, 255, .60);
  --marker: rgba(28, 56, 95, .07);
  --green: #226B42;
  --verify-word: #8F5E0F;
  --epc-ac: #2E6B4F;  --epc-ac-bg: rgba(46, 107, 79, .13);
  --epc-de: #8F5E0F;  --epc-de-bg: rgba(143, 94, 15, .10);
  --epc-fg: #8A2F2B;  --epc-fg-bg: rgba(138, 47, 43, .12);
  --field: #0F2138;
  --action: #1C385F;
  --action-ink: #F8F8F1;
  --action-ring: transparent;
  --lift: 0 1px 2px rgba(28, 56, 95, .07), 0 10px 26px rgba(28, 56, 95, .09);
  --lift-sm: 0 1px 2px rgba(28, 56, 95, .10);
}

:root[data-theme="dark"] {
  --canvas: #0d1520;
  --ink: #E9EFF7;
  --ink-muted: rgba(233, 239, 247, .62);
  --ink-faint: rgba(233, 239, 247, .55);
  --surface: #131e2c;
  --edge: rgba(233, 239, 247, .13);
  --edge-strong: rgba(233, 239, 247, .22);
  --card: rgba(255, 255, 255, .07);
  --chip: rgba(255, 255, 255, .07);
  --chip-hover: rgba(255, 255, 255, .13);
  --row-hover: rgba(255, 255, 255, .06);
  --marker: rgba(255, 255, 255, .08);
  --green: #6FBF8E;
  --verify-word: #D9BA85;
  --epc-ac: #6FBF92;  --epc-ac-bg: rgba(111, 191, 146, .15);
  --epc-de: #D9BA85;  --epc-de-bg: rgba(217, 186, 133, .15);
  --epc-fg: #E08F88;  --epc-fg-bg: rgba(224, 143, 136, .15);
  --field: #050c15;
  --action: #050c15;
  --action-ink: #E9EFF7;
  --action-ring: rgba(233, 239, 247, .42);
  --lift: 0 1px 2px rgba(0, 0, 0, .45), 0 12px 30px rgba(0, 0, 0, .40);
  --lift-sm: 0 1px 2px rgba(0, 0, 0, .45);
}

* { box-sizing: border-box; }

html { height: 100%; }

body {
  margin: 0;
  min-height: 100%;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15.5px;
  line-height: 1.5;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.w { color: var(--verify-word); }
.is-absent { color: var(--ink-muted); }
.is-emph { color: var(--green); }
.vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

a { color: inherit; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; text-align: left; }
input { font: inherit; color: inherit; }
summary::-webkit-details-marker { display: none; }
summary { list-style: none; cursor: pointer; }

:focus-visible { outline: 2px solid var(--ink-muted); outline-offset: 2px; }
.bar :focus-visible { outline-color: rgba(255, 255, 255, .85); }

/* ---------- the shell: rail, main, inner stage ---------- */

.app {
  position: relative;
  display: flex;
  align-items: stretch;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}

.rail {
  display: none;
  flex: 0 0 72px;
  width: 72px;
  padding: 16px 8px 40px;
  flex-direction: column;
  gap: 4px;
}
.rail-item {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  min-width: 0;
  padding: 9px 2px 8px;
  border-radius: var(--r-md);
  color: var(--ink-muted);
  text-decoration: none;
  font-size: 11px;
  line-height: 1.1;
}
.rail-item:hover { background: var(--row-hover); color: var(--ink); }
.rail-item.is-active { background: var(--action); color: var(--action-ink); box-shadow: inset 0 0 0 1px var(--action-ring); }
.rail-item--last { margin-top: auto; }
.rail-item svg { display: block; }

/* A destination without an entity behind it, or without a page yet, is quiet
   and carries no href: it is not a link, so it is not focusable either. */
.rail-item.is-quiet, .tab.is-quiet { opacity: .5; cursor: default; }
.rail-item.is-quiet:hover, .tab.is-quiet:hover { background: none; color: var(--ink-muted); }

/* The label never widens the 72px rail: it clips before the geometry moves. */
.dest-t { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The column is at least the window and grows past it if a page has more to
   say: the shell scrolls there, the frame law bends before the data does. */
.main {
  flex: 1 1 auto;
  min-width: 0;
  padding: 20px 18px 24px;
  overflow-y: auto;
}
.inner {
  width: 100%;
  max-width: 1040px;
  margin: 0 auto;
  min-height: 100%;
  display: flex;
  flex-direction: column;
}
/* A pane page pins the column to the window instead, which is what makes
   .panes take the leftover height and each .pane scroll inside itself. */
.inner--fit { height: 100%; min-height: 0; }

.tabbar {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  display: flex;
  gap: 2px;
  padding: 8px 6px 10px;
  background: var(--canvas);
  box-shadow: 0 -1px 0 var(--edge);
}
.tab {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 6px 2px;
  border-radius: 12px;
  color: var(--ink-muted);
  text-decoration: none;
  font-size: 11px;
  line-height: 1.1;
}
.tab.is-active { background: var(--action); color: var(--action-ink); box-shadow: inset 0 0 0 1px var(--action-ring); }
.tab svg { display: block; }

@media (max-width: 767px) { .main { padding-bottom: 78px; } }
@media (min-width: 768px) {
  .rail { display: flex; }
  .tabbar { display: none; }
  .main { padding: 22px 24px 26px; }
}

/* The sign-in page is not the app, so base.html leaves the rail and the tab bar
   out of it entirely. Two things follow: no room is reserved for a tab bar that
   is not there, and the language toggle drops back into the footer instead of
   standing alone in the gutter the rail used to fill. */
@media screen and (max-width: 767px) { .app--bare .main { padding-bottom: 24px; } }
@media (min-width: 768px) {
  .app--bare .lang { position: static; width: auto; text-align: left; }
}

/* The pip a destination wears when something new landed there. */
.new-pip {
  position: absolute;
  top: 6px; right: 14px;
  width: 8px; height: 8px;
  border-radius: 999px;
  background: var(--ink);
  box-shadow: 0 0 0 2px var(--canvas);
}

/* ---------- language and sources: the quiet chrome ---------- */

/* One node, two homes. On a phone it sits with the sources line at the foot of
   the column; from 768px up it is pinned under the rail. Absolute against .app,
   so the scrolling main neither carries it nor clips it. */
.lang { font-size: 13px; color: var(--ink-faint); }
/* Two letters are a small thing to hit. The link stays inline, where padding
   is hit area and nothing else: the line it sits on does not move, and the
   negative margin gives the two letters their own place back. */
.lang a { padding: 15px; margin: 0 -15px; color: var(--ink-faint); text-decoration: none; }
.lang a:focus-visible { outline-offset: -13px; }
.lang a:hover { color: var(--ink); }
.lang-nu { color: var(--ink); }

.foot {
  margin-top: auto;
  padding-top: 22px;
  font-size: 12.5px;
  color: var(--ink-faint);
}

@media (min-width: 768px) {
  .lang { position: absolute; left: 0; bottom: 12px; width: 72px; text-align: center; }
}

/* ---------- home ---------- */

.home { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 22px; padding-bottom: 14px; }
@media (max-width: 520px) { .home { gap: 16px; } }
.home-mark { margin: 0; font-size: 26px; font-weight: 600; letter-spacing: -.01em; text-align: center; }
.home-line { margin: 6px 0 0; font-size: 13px; color: var(--ink-muted); text-align: center; }
.home-block { width: 100%; max-width: 620px; }

/* ---------- the search field ---------- */

.field {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 60px;
  padding: 0 8px;
  border: 1px solid var(--edge);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--lift);
}
.field-in { flex: 1 1 auto; min-width: 0; height: 100%; border: 0; background: none; font-size: 17px; padding: 0 2px; }
.field-in::placeholder { color: var(--ink-faint); }
.field-in:focus { outline: none; }
/* One ring, and it is the input's own. A box-shadow at the field's outer
   radius rather than an outline nested inside it: the wrapper no longer darkens
   its border, so the field lights up once, on the strip the caret sits in, and
   the ring stands clear of the placeholder instead of cutting a box through it. */
.field-in:focus-visible { outline: none; border-radius: var(--r-lg); box-shadow: 0 0 0 2px var(--ink-muted); }

/* The glyph buttons, chips, pills and doors below all reach the 44px
   hand-sized target the same way: a transparent border carries the extra hit
   area, a negative margin of the same size hands the layout back, and
   background-clip keeps the ground inside the padding box. The ink stays
   exactly where D4 drew it; only the box the finger lands on grows, and
   outline-offset walks the focus ring back onto that ink. */
.ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px; height: 44px;
  margin: -1px;
  border: 1px solid transparent;
  border-radius: 12px;
  background-clip: padding-box;
  color: var(--ink-muted);
}
.ico:hover { background: var(--marker); color: var(--ink); }
.ico:active { transform: scale(.94); }
.send {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px; height: 44px;
  border-radius: 999px;
  background: var(--action);
  color: var(--action-ink);
  box-shadow: inset 0 0 0 1px var(--action-ring);
}
.send:hover { opacity: .88; }
.send:active { transform: scale(.94); }

/* ---------- chips, tags, pills ---------- */

/* margin:0 because these also run as paragraphs, which carry a UA margin */
.chiprow { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0; }
.chiprow--mid { justify-content: center; margin-top: 16px; }
.recents { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-top: 8px; }
.mini { margin: 0 0 8px; font-size: 12.5px; color: var(--ink-muted); text-align: center; }
.mini--l { text-align: left; }

/* The hairline is an inset ring rather than a border, because the border is
   the hit area now: a ring drawn from the padding edge stands exactly where
   D4's own 1px border stood. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: -5px;
  padding: 9px 15px;
  border: 5px solid transparent;
  border-radius: 999px;
  background-clip: padding-box;
  box-shadow: inset 0 0 0 1px var(--edge-strong);
  color: var(--ink);
  font-size: 13px;
  line-height: 1.3;
  white-space: nowrap;
  text-decoration: none;
}
.chip:focus-visible { outline-offset: -3px; }
.chip:hover { background: var(--chip-hover); }
.chip:active { transform: scale(.96); background: var(--marker); }
.chip--quiet { background: var(--chip); color: var(--ink-muted); box-shadow: none; }
.chip--quiet:hover { color: var(--ink); }
.chip--solid { background: var(--action); color: var(--action-ink); box-shadow: inset 0 0 0 1px var(--action-ring); }
.chip--solid:hover { opacity: .88; background: var(--action); }
.chip--light { background: var(--field-ink); color: var(--field); font-weight: 500; box-shadow: none; }
.chip--light:hover { background: var(--field-ink); opacity: .90; }

.rpill {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin: -5px;
  padding: 9px 15px 9px 13px;
  border: 5px solid transparent;
  border-radius: 999px;
  background: var(--card);
  background-clip: padding-box;
  box-shadow: inset 0 0 0 1px var(--edge);
  font-size: 13px;
  white-space: nowrap;
  text-decoration: none;
}
.rpill:focus-visible { outline-offset: -3px; }
.rpill:hover { background: var(--chip-hover); }
.rpill:active { transform: scale(.98); }
.rpill .id { font-family: var(--mono); font-size: 12.5px; color: var(--ink-muted); }

.dot { display: inline-block; width: 7px; height: 7px; border-radius: 999px; background: var(--ink-faint); }
.dot--flag { background: var(--verify-word); }
.dot--on { background: var(--green); }

.tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  border-radius: 999px;
  background: var(--marker);
  color: var(--ink-muted);
  font-size: 12.5px;
  line-height: 1.3;
  white-space: nowrap;
}
.tag .m { font-family: var(--mono); color: var(--ink); }
.badge {
  display: inline-block;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--marker);
  color: var(--ink-muted);
  font-size: 12.5px;
  line-height: 1.35;
  white-space: nowrap;
}
.badge--flag { color: var(--verify-word); }

/* ---------- entity head ---------- */

.head { display: flex; align-items: flex-start; gap: 16px; margin-bottom: 14px; }
.head-l { flex: 1 1 auto; min-width: 0; }
.head-t { margin: 0 0 8px; font-size: 22px; font-weight: 600; line-height: 1.25; }
.head-r { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
.fresh { margin: 0; font-family: var(--mono); font-size: 11px; color: var(--ink-faint); white-space: nowrap; }

/* Under 640 the shared head stacks: the title and its chips take the full
   width instead of being squeezed into a column two words wide, and the pin,
   the save door and the stamp drop to their own row below. owner.css already
   does this for the owner page; here it reaches the property and insight heads
   the same sheet draws. */
@media (max-width: 639px) {
  .head { flex-direction: column; align-items: stretch; gap: 10px; }
  .head-r { flex-direction: row; align-items: center; flex-wrap: wrap; gap: 8px 12px; }
}

.pin { position: relative; display: inline-flex; }
/* inset -3px: the face draws 38px, the box the hand meets reaches 44px. */
.pin-in { position: absolute; inset: -3px; width: auto; height: auto; margin: 0; opacity: 0; cursor: pointer; }
.pin-face { display: inline-flex; align-items: center; justify-content: center; width: 38px; height: 38px; border-radius: 12px; color: var(--ink-muted); }
.pin-in:hover ~ .pin-face { background: var(--row-hover); color: var(--ink); }
.pin-in:checked ~ .pin-face { background: var(--action); color: var(--action-ink); box-shadow: inset 0 0 0 1px var(--action-ring); }
.pin-in:focus-visible ~ .pin-face { outline: 2px solid var(--ink-muted); outline-offset: 2px; }

/* ---------- the one coloured field, as a bar ---------- */

.bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 16px;
  margin: 0 0 14px;
  padding: 14px 16px;
  border-radius: var(--r-lg);
  background: var(--field);
  color: var(--field-ink);
  /* The field is near-black on the dark canvas, so shadow alone does not show
     where it ends: the action-ring draws its boundary. In light the ring is
     transparent and the lift carries the raise, exactly as before. */
  box-shadow: inset 0 0 0 1px var(--action-ring), var(--lift);
}
.bar-t { flex: 1 1 300px; font-size: 17px; line-height: 1.4; }
.bar-t .w { color: var(--verify); }
.bar-acts { display: flex; flex-wrap: wrap; gap: 8px; }
.door {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: -5px;
  padding: 8px 13px;
  border: 5px solid transparent;
  border-radius: 999px;
  background: var(--field-door);
  background-clip: padding-box;
  color: var(--field-ink);
  font-size: 13px;
  text-decoration: none;
  white-space: nowrap;
}
.door:focus-visible { outline-offset: -3px; }
.door:hover { background: var(--field-door-hover); }
.door:active { transform: scale(.97); }

/* ---------- segmented switcher ---------- */

/* flex:none because the switcher is also a flex ITEM of the pinned column, and
   a scroll container's automatic minimum size is zero: a narrow window would
   otherwise squeeze it to a sliver with its own labels clipped inside it. Too
   many words for the width is what overflow-x is there for: it scrolls
   sideways, it never gets shorter. */
.seg {
  position: relative;
  display: flex;
  flex: none;
  gap: 2px;
  align-self: flex-start;
  max-width: 100%;
  margin: 0 0 14px;
  padding: 5px;
  border-radius: 999px;
  background: var(--marker);
  overflow-x: auto;
}
.seg-thumb {
  position: absolute;
  top: 5px; bottom: 5px; left: 0;
  width: 0;
  border-radius: 999px;
  background: var(--surface);
  box-shadow: var(--lift-sm);
}
/* The button's hit area fills the switcher's own padding, which grew by a
   pixel on each side to hold it: the thumb keeps its air and the label its
   place, and the pill never becomes a scroller in the block axis. */
.seg-btn {
  position: relative;
  z-index: 1;
  margin-block: -5px;
  padding: 8px 15px;
  border-block: 5px solid transparent;
  border-radius: 999px;
  background-clip: padding-box;
  color: var(--ink-muted);
  font-size: 13px;
  white-space: nowrap;
}
.seg-btn:focus-visible { outline-offset: -3px; }
.seg-btn:hover { color: var(--ink); }
/* Without JS the active button carries its own ground. With JS the thumb does,
   so the button hands the ground over the moment the switcher goes live. */
.seg-btn.is-on { color: var(--ink); font-weight: 500; background: var(--surface); box-shadow: var(--lift-sm); }
.seg.is-live .seg-btn.is-on { background: transparent; box-shadow: none; }

/* ---------- panes: stacked in one cell, crossfaded ---------- */

.panes { position: relative; flex: 1 1 auto; min-height: 0; display: grid; grid-template-rows: minmax(0, 1fr); }
.pane { grid-area: 1 / 1; min-height: 0; overflow: auto; opacity: 0; visibility: hidden; transform: translateY(4px); }
.pane.is-on { opacity: 1; visibility: visible; transform: none; }
.pane--fit { overflow: hidden; display: flex; flex-direction: column; }

/* A phone window has no leftover height to hand out: the head and the field
   alone can fill it, and the panes are left with the crumbs. What that draws is
   a tile cut through its own last line, or nothing at all. Below the rail's
   breakpoint a pane page is a document instead: the pane that is on stands at
   its full height and the shell scrolls down it, the bend the note on .main
   already allows. Only the pane that is on is drawn, so the switch is instant
   rather than a crossfade; a phone that cannot show the pane at all is the
   worse trade, and reduced motion never had the crossfade anyway.

   `screen and`, because these selectors are heavier than the print sheet's own
   and would otherwise follow a narrow paper size onto the page: on paper every
   pane is printed, one after the other, and none of them is a window. */
@media screen and (max-width: 767px) {
  .inner--fit:has(.panes) { height: auto; min-height: 100%; }
  .panes { display: block; }
  .pane { display: none; }
  .pane.is-on { display: block; overflow: visible; }
  .pane--fit.is-on { display: flex; overflow: visible; }
}

@media (prefers-reduced-motion: no-preference) {
  .pane { transition: opacity 200ms ease, transform 200ms var(--spring), visibility 0s linear 200ms; }
  .pane.is-on { transition: opacity 200ms ease, transform 240ms var(--spring), visibility 0s; }
  .seg-thumb { transition: transform 280ms var(--spring), width 280ms var(--spring); }
  .chip, .tile, .rail-item, .tab, .door, .rpill, .lrow, .ico, .send, .pin-face, .seg-btn, .cand { transition: background-color 150ms ease, color 150ms ease, transform 180ms var(--spring), opacity 150ms ease; }
  .switch-face, .switch-knob { transition: background-color 200ms ease, transform 220ms var(--spring); }
  details[open] > .pop { animation: pop-in 180ms var(--spring); }
}
@keyframes pop-in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }

/* ---------- tile grid ---------- */

.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px; align-content: start; }
.tiles--4 { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
.tile {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 14px 15px 13px;
  border: 1px solid var(--edge);
  border-radius: var(--r-md);
  background: var(--card);
}
/* display:block because these also run as spans inside button tiles */
.tile-l { display: block; margin: 0; font-size: 12.5px; color: var(--ink-muted); }
.tile-v { display: block; margin: 5px 0 0; font-size: 22px; line-height: 1.2; letter-spacing: -.01em; }
/* A tile is a flex column now, so a value sits at the baseline whatever line
   count its label wrapped to: down a row the values line up. Scoped to the
   tile's own value, so the same class elsewhere (a saved card, an insight
   body) keeps its 5px lead. */
.tile > .tile-v { margin-top: auto; }
.tile-v--w { font-size: 17px; line-height: 1.35; }
.tile-s { display: block; margin: 5px 0 0; font-size: 12.5px; color: var(--ink-faint); }
.tile--go { display: block; width: 100%; text-decoration: none; }
.tile--go:hover { background: var(--chip-hover); border-color: var(--edge-strong); }
.tile--go:active { transform: scale(.99); }
.tile-go { position: absolute; top: 14px; right: 14px; font-size: 13px; color: var(--ink-faint); }
.tile--more:hover { background: var(--chip-hover); }

/* ---------- the popover layer ---------- */

.tile-dot {
  position: absolute;
  top: 1px; right: 1px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 26px;
  border-radius: 999px;
  color: var(--ink-faint);
  /* The dot draws 26px where it always sat; the transparent border grows
     the box the hand meets to 44px without moving a pixel of ink. */
  border: 9px solid transparent;
  background-clip: padding-box;
}
.tile-dot:hover { background: var(--marker); color: var(--ink); }
details[open] > .tile-dot { background: var(--action); color: var(--action-ink); box-shadow: inset 0 0 0 1px var(--action-ring); }
details[open] > .tile-dot svg { transform: rotate(180deg); }

.pop {
  position: absolute;
  top: calc(100% - 4px);
  left: 0;
  z-index: 5;
  width: min(320px, 80vw);
  padding: 16px 16px 14px;
  border: 1px solid var(--edge-strong);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--lift);
}
.pop-t { margin: 0 0 6px; font-size: 15.5px; font-weight: 600; }
.pop-l { margin: 0 0 8px; font-size: 13px; color: var(--ink-muted); }
.pop-acts { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0 0; }
.stamp { margin: 12px 0 0; font-family: var(--mono); font-size: 11px; line-height: 1.7; color: var(--ink-faint); }
.stamp span { display: inline-block; margin-right: 14px; }

/* ---------- lists that scroll inside the frame ---------- */

.listwrap { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; margin-top: 14px; }
.list { flex: 1 1 auto; min-height: 0; overflow: auto; margin: 0 -8px; padding: 0 8px; }
.lgroup {
  position: sticky; top: 0;
  margin: 0;
  padding: 6px 4px;
  background: var(--canvas);
  font-size: 12.5px;
  color: var(--ink-muted);
}
.lrow {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 12px;
  width: 100%;
  min-height: 52px;
  padding: 10px 12px;
  border-radius: 12px;
  color: inherit;
  text-decoration: none;
}
.lrow:hover { background: var(--row-hover); }
.lrow:active { transform: scale(.995); }
.lrow-t { flex: 1 1 200px; min-width: 0; font-size: 15.5px; }
.lrow-id { font-family: var(--mono); font-size: 13px; color: var(--ink-muted); }
.lrow-f { display: flex; flex-wrap: wrap; gap: 6px; }
.lrow-go { font-size: 13px; color: var(--ink-faint); }

/* ---------- cards and stats ---------- */

.card { padding: 16px 18px; border: 1px solid var(--edge); border-radius: var(--r-md); background: var(--card); }
.card--lift { background: var(--surface); box-shadow: var(--lift); border-color: var(--edge); }
.card-t { margin: 0 0 10px; font-size: 15.5px; font-weight: 600; }
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; align-content: start; }
.cardhead { display: flex; align-items: baseline; gap: 12px; }
.cardhead .fresh { margin-left: auto; }
.stack { display: flex; flex-direction: column; gap: 12px; }

/* Few tiles must not balloon. On a wide frame the tracks stop stretching to
   1fr and cap, left-aligned, so two or three cards keep tile proportions
   instead of a lone value floating in an empty box. A phone keeps the filling
   1fr from the base rules, where one column is the whole width and the cap
   would only strand a card against dead space. */
@media (min-width: 768px) {
  .tiles { grid-template-columns: repeat(auto-fill, minmax(190px, 260px)); justify-content: start; }
  .tiles--4 { grid-template-columns: repeat(auto-fill, minmax(160px, 220px)); }
  .cards { grid-template-columns: repeat(auto-fill, minmax(220px, 280px)); justify-content: start; }
}

.statrow {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px 8px;
  padding: 14px 16px;
  border: 1px solid var(--edge);
  border-radius: var(--r-md);
  background: var(--card);
}
@media (max-width: 520px) { .statrow { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.stat-v { margin: 0; font-family: var(--mono); font-size: 22px; line-height: 1.15; letter-spacing: -.01em; }
.stat-l { margin: 3px 0 0; font-size: 11px; line-height: 1.35; color: var(--ink-muted); }

/* ---------- switch ---------- */

.srow { position: relative; display: flex; align-items: center; gap: 14px; min-height: 48px; padding: 4px 0; cursor: pointer; }
.srow-t { flex: 1 1 auto; font-size: 15.5px; }
.srow-s { display: block; margin: 2px 0 0; font-size: 12.5px; color: var(--ink-muted); }
.switch-in { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.switch-face {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  width: 48px; height: 28px;
  padding: 3px;
  border-radius: 999px;
  background: var(--marker);
  box-shadow: inset 0 0 0 1px var(--edge);
}
.switch-knob { width: 22px; height: 22px; border-radius: 999px; background: var(--surface); box-shadow: var(--lift-sm); }
.switch-in:checked ~ .switch-face { background: var(--action); box-shadow: inset 0 0 0 1px var(--action-ring); }
.switch-in:checked ~ .switch-face .switch-knob { transform: translateX(20px); }
.switch-in:focus-visible ~ .switch-face { outline: 2px solid var(--ink-muted); outline-offset: 2px; }
.switch-in:hover ~ .switch-face { background: var(--edge); }
.switch-in:checked:hover ~ .switch-face { background: var(--action); }

/* ---------- calm and empty states ---------- */

/* min-height:100% so it also centres inside a pane, which is a block, not a flex row */
.calm { flex: 1 1 auto; min-height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 14px; text-align: center; padding-bottom: 20px; }
.calm-t { margin: 0; font-size: 22px; font-weight: 600; }
.calm-l { margin: 0; max-width: 380px; font-size: 13px; color: var(--ink-muted); }
.msg { margin: 14px 0 0; font-size: 15.5px; color: var(--ink-muted); }
.msg-s { margin: 8px 0 0; font-size: 12.5px; color: var(--ink-faint); }
.cand {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 12px 14px;
  border: 1px solid var(--edge-strong);
  border-radius: var(--r-md);
  background: var(--chip);
  font-size: 15.5px;
  text-decoration: none;
}
.cand:hover { background: var(--chip-hover); }
.cand:active { transform: scale(.99); }
.cand span { font-family: var(--mono); font-size: 12.5px; color: var(--ink-muted); }

/* a block that takes the leftover height and scrolls inside itself, so a short
   window shortens the box instead of pushing the frame open */
.fillscroll { flex: 1 1 auto; min-height: 0; overflow: auto; }

/* ---------- epc chips ---------- */

.epc {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px; height: 18px;
  border-radius: 5px;
  font-family: var(--mono);
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1;
  vertical-align: -3px;
}
.epc--lg { width: 28px; height: 28px; border-radius: 8px; font-size: 15.5px; vertical-align: -5px; }
.epc--ac { background: var(--epc-ac-bg); color: var(--epc-ac); }
.epc--de { background: var(--epc-de-bg); color: var(--epc-de); }
.epc--fg { background: var(--epc-fg-bg); color: var(--epc-fg); }
/* An expired or absent label goes grey: it does not carry its colour past its
   validity. Muted ink, not faint: faint on the marker ground measures 4.33:1. */
.epc--out, .epc--ude { background: var(--marker); color: var(--ink-muted); }

/* ---------- the quick switcher (cmd K), drawn by linse.js ---------- */

.qs {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: flex;
  justify-content: center;
  padding: 12vh 18px 18px;
  background: rgba(15, 33, 56, .22);
}
.qs[hidden] { display: none; }
.qs-box { width: 100%; max-width: 560px; align-self: flex-start; }
.qs-list {
  margin: 8px 0 0;
  padding: 6px;
  border: 1px solid var(--edge);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--lift);
  list-style: none;
}
.qs-list[hidden] { display: none; }
.qs-list li { padding: 10px 12px; border-radius: var(--r-sm); font-size: 15.5px; cursor: pointer; }
.qs-list li:hover, .qs-list li.is-on { background: var(--marker); }
/* the line that says the list is not the whole answer: not a suggestion, not
   pickable, not clickable */
.qs-list li.qs-more { font-size: 12.5px; color: var(--ink-faint); cursor: default; }
.qs-list li.qs-more:hover { background: none; }
.qs-hint { margin: 10px 4px 0; font-size: 12.5px; color: var(--ink-faint); }

/* ---------- home: the mark beside the line ---------- */

/* The ruled P sits with the greeting, the way the icon sits beside its app's
   first line. The two fills are tokens, so the mark is navy on paper and paper
   on navy without a second drawing of it. */
.home-id { display: flex; align-items: center; justify-content: center; gap: 14px; }
.home-p { flex: 0 0 auto; display: block; width: 30px; height: 30px; }
.home-id .home-mark, .home-id .home-line { text-align: left; }

/* The suggestions hang under the field instead of pushing the column down:
   the answer arrives without the page moving under the hand. */
.acbox { position: relative; }
.acbox .qs-list { position: absolute; left: 0; right: 0; top: calc(100% + 8px); z-index: 6; margin: 0; }

/* ---------- the discover card: the app giving something back ---------- */

.give {
  position: relative;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px 18px;
  border-radius: var(--r-lg);
  background: var(--field);
  color: var(--field-ink);
  box-shadow: var(--lift);
  overflow: hidden;
}
/* dismissing takes the wrapper with it, so no empty gap is left behind */
.give:has(.give-in:checked), .home-block:has(.give-in:checked) { display: none; }
.give-l { flex: 1 1 auto; min-width: 0; }
.give-t { margin: 0; font-size: 15.5px; line-height: 1.4; }
.give-s { margin: 4px 0 0; font-size: 12.5px; color: var(--field-soft); }
.give-acts { margin: 12px 0 0; }
.give-art { flex: 0 0 auto; opacity: .85; }
@media (max-width: 520px) { .give-art { display: none; } }
.give-x {
  position: absolute;
  top: 8px; right: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px; height: 28px;
  border-radius: 999px;
  color: var(--field-soft);
  pointer-events: none;
}
/* the dismiss input covers only the corner, so the pill under it stays clickable */
.give-in { position: absolute; top: 8px; right: 8px; z-index: 2; width: 28px; height: 28px; margin: 0; opacity: 0; cursor: pointer; }
.give-in:hover ~ .give-x { background: var(--field-door); color: var(--field-ink); }
.give-in:focus-visible ~ .give-x { outline: 2px solid rgba(255, 255, 255, .85); outline-offset: 2px; }

/* ---------- the rest of the furniture these three pages need ---------- */

/* The doors of a page whose verdict bar was not earned: same set, quiet ground.
   (D4 addendum 4: the panel goes, its doors move up into the header row.) */
.chiprow--head { margin-bottom: 14px; }

/* The candidates under a question the page just asked. */
.cards--gap { margin-top: 12px; }

/* A chip that carries a state, not just a destination: the kind the field is
   set to, or the filter the page is already showing. */
.chip[aria-pressed="true"], .chip[aria-current="true"] { border-color: transparent; background: var(--action); color: var(--action-ink); box-shadow: inset 0 0 0 1px var(--action-ring); }

/* The severity word in front of a flag sentence. Amber is the verify word and
   nothing else, so a watch or a note wears the field's own quiet ink. */
.bar-sev { color: var(--field-soft); }

/* The engine's own flag sentences, as given. */
.noteline { margin: 0 0 8px; font-size: 13px; line-height: 1.55; color: var(--ink-muted); }
.noteline:last-child { margin-bottom: 0; }

/* A row with two doors in it is not a door itself: it takes no hover ground,
   and the two links inside it carry the reaction instead. */
.lrow--pair:hover { background: none; }
.lrow--pair:active { transform: none; }
.lrow-t a, .lrow-o { text-decoration: none; }
.lrow-t a:hover, .lrow-o:hover { text-decoration: underline; }
.lrow-o { font-size: 13px; color: var(--ink-muted); }
/* The two doors in one row are words, not chips, so they take their hand-sized
   box the way a word can: the address is inline, where padding is hit area
   alone; the owner is a flex item, so its border carries the same reach and a
   negative margin hands the row's height back. Neither word moves. */
.lrow-t a { padding: 14px; margin-inline: -14px; }
.lrow-t a:focus-visible { outline-offset: -12px; }
a.lrow-o { margin: -13px; border: 13px solid transparent; }
a.lrow-o:focus-visible { outline-offset: -11px; }

/* Down a portfolio or a nearby list the attributes must land on the same
   tracks row to row, not float wherever a shorter address left them. The list
   becomes the grid and every row a subgrid of it, so the address takes the
   slack (1fr) and the chips, the distance and the BFE share columns sized to
   the widest across the whole list. Only from 768 up: a phone keeps the
   wrapping flex row, where a rigid grid would overflow the narrow frame.
   Nearby is read off its shape (a paired row that carries a chip cluster), the
   one list where that combination stands. */
@media (min-width: 768px) {
  .pane[data-pane="portfolio"] .list,
  .list:has(> .lrow--pair > .lrow-f) {
    display: grid;
    align-content: start;
    column-gap: 12px;
  }
  .pane[data-pane="portfolio"] .list { grid-template-columns: minmax(0, 1fr) auto auto; }
  .list:has(> .lrow--pair > .lrow-f) { grid-template-columns: minmax(0, 1fr) auto auto auto; }

  .pane[data-pane="portfolio"] .list > *,
  .list:has(> .lrow--pair > .lrow-f) > * { grid-column: 1 / -1; }

  .pane[data-pane="portfolio"] .lrow,
  .list:has(> .lrow--pair > .lrow-f) > .lrow--pair {
    display: grid;
    grid-template-columns: subgrid;
    align-items: center;
  }
}

/* A pin the browser cannot keep is not shown at all (linse.js sets [hidden]),
   and .pin's own display would otherwise win over the attribute. */
.pin[hidden] { display: none; }

/* ---------- print: the property page as the one page brief ---------- */

.printfoot { display: none; }

@media print {
  @page { margin: 12mm; }

  html, body { height: auto; background: #FFFFFF; color: #000000; font-size: 11px; }

  /* the frame is a window on screen and a sheet on paper: every box that
     clipped or scrolled hands its content back to the flow */
  .app { display: block; height: auto; overflow: visible; }
  .main { padding: 0; overflow: visible; }
  .inner, .inner--fit { max-width: none; height: auto; min-height: 0; display: block; }
  .panes { display: block; }
  .pane {
    display: block;
    margin: 0 0 10px;
    opacity: 1;
    visibility: visible;
    transform: none;
    overflow: visible;
    break-inside: avoid;
  }
  .list, .listwrap, .fillscroll { overflow: visible; }

  /* the controls do not survive the paper: a switcher, a pin and a chip are
     all promises of a click */
  .rail, .tabbar, .qs, .lang, .seg, .pin, .tile-dot, .chip, .door, .send, .ico,
  .give, .new-pip, .statrow, .recents, [data-print], .pane[data-pane="nearby"] { display: none; }

  /* ink, not fields: the deep panel would print as a solid navy block */
  .bar { padding: 8px 10px; background: none; color: #000000; box-shadow: none; border: 1px solid #000000; }
  .bar-t .w, .bar-sev { color: #000000; font-weight: 600; }
  .tile, .card, .cand { background: none; box-shadow: none; border: 1px solid rgba(0, 0, 0, .35); break-inside: avoid; }
  .tiles { gap: 8px; }
  .tile-v { font-size: 15px; }
  .head-t { font-size: 17px; }
  .fresh, .stamp, .lrow-id { color: #000000; }
  .foot { padding-top: 10px; }

  .printfoot { display: block; margin: 12px 0 0; font-size: 11px; }
}

/* ---------- share links (Wave 3, staged) ---------- */
/* The public read-only page carries no .app shell: it flows in the document as a
   narrow centred column on paper, the same tokens as the register cards. The
   foot names PLens and holds the language toggle inline (never the gutter-pinned
   .lang, which has no rail to sit under here). */
.share {
  max-width: 720px;
  margin: 0 auto;
  padding: 28px 18px 40px;
  min-height: 100dvh;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.share-foot {
  margin-top: auto;
  padding-top: 24px;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px 16px;
}
.share-mark { margin: 0; font-size: 13px; font-weight: 600; color: var(--ink-muted); }
.share-lang { font-size: 13px; color: var(--ink-faint); }
.share-lang a { color: var(--ink-faint); text-decoration: none; padding: 8px; margin: 0 -8px; }
.share-lang a:hover { color: var(--ink); }
.share-lang .lang-nu { color: var(--ink); }

/* The Share affordance on Property and Saved: a quiet disclosure holding the
   copyable capability URL. Only ever rendered behind the flag. */
.share-drop { position: relative; }
.share-pop {
  margin-top: 8px;
  padding: 12px 14px;
  border: 1px solid var(--edge);
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--lift-sm);
}
.share-note { margin: 0 0 8px; font-size: 12.5px; color: var(--ink-muted); }
.share-url { display: block; font-family: var(--mono); font-size: 12.5px; word-break: break-all; color: var(--ink); text-decoration: none; }
.share-url:hover { text-decoration: underline; }
.share-list { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 0 0 14px; }
