contacts-pane 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"contactsPane.js","mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,O;;;;;;;;;;;;;;;;ACVA;AAC6G;AACjB;AACO;AACnG,4CAA4C,kEAAka;AAC9c,8BAA8B,mFAA2B,CAAC,4FAAqC;AAC/F,yCAAyC,sFAA+B;AACxE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,qBAAqB;AACrB,uBAAuB;AACvB;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,0BAA0B,mCAAmC;AAC7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,qBAAqB;AACrB;AACA;AACA;AACA,eAAe;AACf;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA,oBAAoB;AACpB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AAC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kB,wBAAwB,GAAG,mCAAmC,iBAAiB,GAAG,mBAAmB;AACzrpB;AACA,iEAAe,uBAAuB,EAAC;;;;;;;;;;;;;;;ACnmBvC;AAC6G;AACjB;AAC5F,8BAA8B,mFAA2B,CAAC,4FAAqC;AAC/F;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,OAAO,kHAAkH,aAAa,OAAO,YAAY,WAAW,MAAM,MAAM,YAAY,OAAO,MAAM,YAAY,OAAO,KAAK,OAAO,MAAM,YAAY,aAAa,aAAa,OAAO,KAAK,UAAU,UAAU,YAAY,aAAa,aAAa,OAAO,MAAM,YAAY,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,WAAW,YAAY,aAAa,aAAa,OAAO,MAAM,YAAY,aAAa,aAAa,OAAO,MAAM,YAAY,aAAa,OAAO,MAAM,YAAY,OAAO,MAAM,YAAY,OAAO,MAAM,YAAY,aAAa,aAAa,aAAa,aAAa,aAAa,OAAO,YAAY,SAAS,YAAY,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,OAAO,YAAY,OAAO,YAAY,aAAa,aAAa,aAAa,OAAO,YAAY,OAAO,YAAY,OAAO,MAAM,YAAY,OAAO,KAAK,YAAY,aAAa,OAAO,YAAY,SAAS,YAAY,OAAO,YAAY,SAAS,YAAY,OAAO,MAAM,YAAY,aAAa,OAAO,MAAM,UAAU,UAAU,UAAU,YAAY,WAAW,YAAY,aAAa,aAAa,aAAa,aAAa,OAAO,QAAQ,YAAY,aAAa,aAAa,aAAa,WAAW,UAAU,YAAY,WAAW,YAAY,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,OAAO,MAAM,UAAU,UAAU,YAAY,WAAW,YAAY,aAAa,aAAa,OAAO,cAAc,YAAY,OAAO,cAAc,YAAY,aAAa,aAAa,OAAO,MAAM,UAAU,MAAM,MAAM,UAAU,YAAY,OAAO,MAAM,YAAY,aAAa,OAAO,MAAM,YAAY,aAAa,OAAO,MAAM,UAAU,MAAM,QAAQ,YAAY,WAAW,OAAO,YAAY,OAAO,YAAY,WAAW,OAAO,MAAM,UAAU,YAAY,aAAa,OAAO,MAAM,UAAU,UAAU,YAAY,aAAa,aAAa,OAAO,MAAM,YAAY,aAAa,aAAa,OAAO,MAAM,YAAY,aAAa,OAAO,YAAY,SAAS,YAAY,aAAa,OAAO,YAAY,OAAO,YAAY,aAAa,OAAO,YAAY,OAAO,UAAU,YAAY,aAAa,OAAO,YAAY,aAAa,OAAO,UAAU,YAAY,OAAO,MAAM,YAAY,OAAO,YAAY,aAAa,OAAO,UAAU,YAAY,WAAW,YAAY,aAAa,OAAO,MAAM,YAAY,OAAO,MAAM,YAAY,OAAO,MAAM,YAAY,OAAO,MAAM,YAAY,OAAO,cAAc,YAAY,aAAa,aAAa,OAAO,cAAc,YAAY,aAAa,aAAa,WAAW,UAAU,MAAM,YAAY,OAAO,YAAY,OAAO,MAAM,YAAY,aAAa,OAAO,YAAY,OAAO,YAAY,OAAO,MAAM,YAAY,OAAO,MAAM,YAAY,OAAO,QAAQ,YAAY,OAAO,MAAM,YAAY,OAAO,kBAAkB,YAAY,aAAa,aAAa,aAAa,OAAO,KAAK,YAAY,OAAO,YAAY,aAAa,MAAM,QAAQ,cAAc,aAAa,aAAa,MAAM,YAAY,OAAO,KAAK,YAAY,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,OAAO,MAAM,YAAY,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,OAAO,YAAY,OAAO,YAAY,OAAO,YAAY,OAAO,YAAY,aAAa,aAAa,aAAa,4PAA4P,wBAAwB,kBAAkB,GAAG,wJAAwJ,2BAA2B,GAAG,iEAAiE,uBAAuB,GAAG,8MAA8M,2BAA2B,8BAA8B,8CAA8C,GAAG,+CAA+C,mBAAmB,iBAAiB,4BAA4B,2BAA2B,wBAAwB,GAAG,8GAA8G,6CAA6C,4BAA4B,yBAAyB,gCAAgC,2CAA2C,wCAAwC,uCAAuC,oBAAoB,yBAAyB,wBAAwB,4BAA4B,GAAG,4HAA4H,yBAAyB,wBAAwB,oCAAoC,GAAG,wHAAwH,yBAAyB,wBAAwB,GAAG,sIAAsI,oCAAoC,GAAG,0HAA0H,yDAAyD,GAAG,sGAAsG,yDAAyD,4BAA4B,yBAAyB,gCAAgC,gCAAgC,iEAAiE,GAAG,yQAAyQ,4BAA4B,6BAA6B,+BAA+B,gCAAgC,wBAAwB,0BAA0B,2BAA2B,GAAG,yNAAyN,sDAAsD,+BAA+B,+BAA+B,sCAAsC,GAAG,wMAAwM,6BAA6B,GAAG,2KAA2K,oCAAoC,GAAG,gFAAgF,0BAA0B,2BAA2B,GAAG,8YAA8Y,oCAAoC,GAAG,0VAA0V,oCAAoC,GAAG,kDAAkD,wCAAwC,uCAAuC,GAAG,4FAA4F,eAAe,mBAAmB,iBAAiB,2BAA2B,kBAAkB,6BAA6B,sDAAsD,+CAA+C,8BAA8B,+BAA+B,GAAG,yIAAyI,qBAAqB,6BAA6B,sDAAsD,kFAAkF,eAAe,mBAAmB,2BAA2B,kBAAkB,6BAA6B,sDAAsD,yBAAyB,kCAAkC,8BAA8B,+BAA+B,0CAA0C,GAAG,kDAAkD,mBAAmB,iBAAiB,2BAA2B,kBAAkB,6BAA6B,sDAAsD,+CAA+C,GAAG,gZAAgZ,wCAAwC,GAAG,oeAAoe,2EAA2E,wBAAwB,kDAAkD,GAAG,4EAA4E,eAAe,GAAG,oEAAoE,iBAAiB,qCAAqC,GAAG,gFAAgF,yBAAyB,0BAA0B,GAAG,0EAA0E,0BAA0B,2BAA2B,GAAG,wJAAwJ,iBAAiB,GAAG,+MAA+M,0BAA0B,mBAAmB,GAAG,2UAA2U,0BAA0B,mBAAmB,GAAG,kFAAkF,eAAe,0BAA0B,+BAA+B,GAAG,wEAAwE,eAAe,mBAAmB,2BAA2B,8BAA8B,+BAA+B,GAAG,4DAA4D,8BAA8B,2BAA2B,yBAAyB,GAAG,4FAA4F,8BAA8B,+BAA+B,GAAG,oRAAoR,4BAA4B,0BAA0B,GAAG,yHAAyH,4BAA4B,0BAA0B,GAAG,iQAAiQ,kBAAkB,0BAA0B,qCAAqC,GAAG,gNAAgN,oBAAoB,qCAAqC,GAAG,kHAAkH,kCAAkC,GAAG,2MAA2M,oBAAoB,qCAAqC,eAAe,gCAAgC,2BAA2B,GAAG,oHAAoH,8BAA8B,GAAG,kIAAkI,8BAA8B,GAAG,oGAAoG,8BAA8B,GAAG,oMAAoM,qBAAqB,GAAG,o8BAAo8B,yBAAyB,wBAAwB,2BAA2B,GAAG,wnCAAwnC,yBAAyB,wBAAwB,2BAA2B,YAAY,iBAAiB,GAAG,kPAAkP,4BAA4B,GAAG,0NAA0N,oCAAoC,mCAAmC,GAAG,sSAAsS,4BAA4B,GAAG,0OAA0O,8CAA8C,GAAG,kKAAkK,2BAA2B,GAAG,6SAA6S,yBAAyB,GAAG,wJAAwJ,6BAA6B,GAAG,wdAAwd,yDAAyD,wBAAwB,2CAA2C,+EAA+E,GAAG,mEAAmE,4BAA4B,GAAG,8lBAA8lB,gCAAgC,GAAG,wFAAwF,uFAAuF,sBAAsB,wBAAwB,0BAA0B,6BAA6B,6BAA6B,oCAAoC,0BAA0B,mCAAmC,2CAA2C,mDAAmD,yEAAyE,wDAAwD,mDAAmD,gDAAgD,uCAAuC,GAAG,gIAAgI,kCAAkC,0CAA0C,4BAA4B,6BAA6B,6BAA6B,wBAAwB,4BAA4B,yBAAyB,2BAA2B,0BAA0B,GAAG,kLAAkL,oCAAoC,GAAG,0VAA0V,wBAAwB,0CAA0C,0BAA0B,2CAA2C,GAAG,mBAAmB;AAChosB;AACA,iEAAe,uBAAuB,EAAC;;;;;;;;;;;;;;;ACzgBvC;AAC6G;AACjB;AAC5F,8BAA8B,mFAA2B,CAAC,4FAAqC;AAC/F;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,yGAAyG,MAAM,YAAY,OAAO,YAAY,MAAM,YAAY,aAAa,aAAa,aAAa,WAAW,UAAU,YAAY,OAAO,KAAK,YAAY,OAAO,YAAY,MAAM,UAAU,YAAY,aAAa,aAAa,OAAO,KAAK,UAAU,YAAY,aAAa,aAAa,aAAa,aAAa,OAAO,YAAY,MAAM,UAAU,YAAY,aAAa,aAAa,OAAO,KAAK,UAAU,YAAY,OAAO,KAAK,UAAU,UAAU,UAAU,MAAM,YAAY,OAAO,YAAY,aAAa,aAAa,aAAa,OAAO,MAAM,YAAY,OAAO,KAAK,YAAY,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,WAAW,YAAY,aAAa,WAAW,MAAM,KAAK,YAAY,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,WAAW,MAAM,KAAK,KAAK,YAAY,aAAa,aAAa,OAAO,KAAK,YAAY,aAAa,MAAM,MAAM,KAAK,KAAK,YAAY,aAAa,MAAM,yIAAyI,iCAAiC,GAAG,4GAA4G,6BAA6B,2EAA2E,sCAAsC,qBAAqB,eAAe,cAAc,2BAA2B,GAAG,4CAA4C,kCAAkC,GAAG,8FAA8F,kBAAkB,2BAA2B,yBAAyB,qBAAqB,GAAG,kDAAkD,gBAAgB,uBAAuB,6CAA6C,0BAA0B,8BAA8B,wCAAwC,GAAG,2IAA2I,kBAAkB,wBAAwB,2BAA2B,qCAAqC,GAAG,qEAAqE,kBAAkB,qBAAqB,GAAG,yEAAyE,iBAAiB,gBAAgB,cAAc,GAAG,gRAAgR,2BAA2B,oCAAoC,kCAAkC,yBAAyB,GAAG,gNAAgN,mCAAmC,GAAG,+HAA+H,kCAAkC,sBAAsB,yBAAyB,2CAA2C,uCAAuC,gCAAgC,+BAA+B,kBAAkB,wBAAwB,4BAA4B,kBAAkB,GAAG,qIAAqI,kCAAkC,yBAAyB,gCAAgC,wCAAwC,6CAA6C,+BAA+B,0CAA0C,kBAAkB,GAAG,+BAA+B,8DAA8D,uDAAuD,wCAAwC,iCAAiC,KAAK,2EAA2E,gDAAgD,0DAA0D,KAAK,GAAG,+BAA+B,8DAA8D,uDAAuD,wCAAwC,KAAK,GAAG,qBAAqB;AAC9kJ;AACA,iEAAe,uBAAuB,EAAC;;;;;;;;;;;;;;;AC1HvC;AAC6G;AACjB;AAC5F,8BAA8B,mFAA2B,CAAC,4FAAqC;AAC/F;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,OAAO,oGAAoG,cAAc,MAAM,YAAY,aAAa,aAAa,aAAa,aAAa,WAAW,gLAAgL,qFAAqF,wCAAwC,6CAA6C,kCAAkC,2BAA2B,oBAAoB,GAAG,mBAAmB;AAC5oB;AACA,iEAAe,uBAAuB,EAAC;;;;;;;;;;;;;;;AClBvC;AAC6G;AACjB;AAC5F,8BAA8B,mFAA2B,CAAC,4FAAqC;AAC/F;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,oGAAoG,aAAa,MAAM,UAAU,UAAU,UAAU,UAAU,UAAU,UAAU,YAAY,WAAW,YAAY,aAAa,OAAO,YAAY,MAAM,YAAY,aAAa,aAAa,WAAW,YAAY,OAAO,YAAY,MAAM,YAAY,WAAW,YAAY,aAAa,OAAO,YAAY,MAAM,YAAY,aAAa,aAAa,aAAa,aAAa,WAAW,YAAY,OAAO,KAAK,YAAY,aAAa,WAAW,qJAAqJ,oBAAoB,WAAW,YAAY,gBAAgB,iBAAiB,kBAAkB,kCAAkC,kBAAkB,4BAA4B,wBAAwB,GAAG,gDAAgD,wCAAwC,+BAA+B,6CAA6C,mBAAmB,wCAAwC,GAAG,6GAA6G,kCAAkC,kBAAkB,4BAA4B,2BAA2B,GAAG,8FAA8F,wCAAwC,iDAAiD,2CAA2C,6CAA6C,qBAAqB,oBAAoB,mDAAmD,GAAG,4CAA4C,qCAAqC,wBAAwB,oBAAoB,GAAG,qBAAqB;AACv0D;AACA,iEAAe,uBAAuB,EAAC;;;;;;;;;;;;;;;ACxDvC;AAC6G;AACjB;AAC5F,8BAA8B,mFAA2B,CAAC,4FAAqC;AAC/F;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,uGAAuG,cAAc,cAAc,MAAM,YAAY,aAAa,aAAa,OAAO,KAAK,YAAY,aAAa,aAAa,aAAa,uRAAuR,qBAAqB,6CAA6C,8BAA8B,GAAG,mDAAmD,yDAAyD,4BAA4B,yBAAyB,gCAAgC,GAAG,qBAAqB;AACx0B;AACA,iEAAe,uBAAuB,EAAC;;;;;;;;;;;;;;;ACxBvC;AAC6G;AACjB;AAC5F,8BAA8B,mFAA2B,CAAC,4FAAqC;AAC/F;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,OAAO,kGAAkG,cAAc,cAAc,MAAM,YAAY,aAAa,aAAa,OAAO,KAAK,YAAY,aAAa,aAAa,aAAa,aAAa,WAAW,OAAO,aAAa,MAAM,UAAU,YAAY,aAAa,OAAO,KAAK,UAAU,UAAU,YAAY,OAAO,aAAa,MAAM,YAAY,OAAO,KAAK,YAAY,8QAA8Q,mCAAmC,8BAA8B,8CAA8C,GAAG,gCAAgC,+BAA+B,0BAA0B,0BAA0B,8BAA8B,qBAAqB,oBAAoB,GAAG,sGAAsG,kBAAkB,2BAA2B,2BAA2B,GAAG,yCAAyC,kBAAkB,oBAAoB,2BAA2B,GAAG,4GAA4G,yCAAyC,GAAG,wCAAwC,2CAA2C,GAAG,qBAAqB;AAC7gD;AACA,iEAAe,uBAAuB,EAAC;;;;;;;;;;;;;;;AClDvC;AAC6G;AACjB;AAC5F,8BAA8B,mFAA2B,CAAC,4FAAqC;AAC/F;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,6FAA6F,MAAM,YAAY,MAAM,YAAY,OAAO,KAAK,YAAY,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,WAAW,YAAY,OAAO,KAAK,YAAY,aAAa,OAAO,KAAK,YAAY,OAAO,KAAK,YAAY,aAAa,WAAW,OAAO,KAAK,YAAY,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,WAAW,YAAY,aAAa,aAAa,aAAa,aAAa,OAAO,KAAK,YAAY,OAAO,KAAK,YAAY,aAAa,OAAO,MAAM,YAAY,aAAa,aAAa,WAAW,yQAAyQ,6BAA6B,GAAG,kBAAkB,wCAAwC,iDAAiD,2CAA2C,6CAA6C,qCAAqC,mCAAmC,qBAAqB,oBAAoB,mDAAmD,GAAG,wBAAwB,oEAAoE,wCAAwC,GAAG,yBAAyB,yCAAyC,GAAG,2BAA2B,qCAAqC,wBAAwB,oBAAoB,GAAG,oBAAoB,wCAAwC,iDAAiD,kEAAkE,6CAA6C,uCAAuC,mCAAmC,yCAAyC,oBAAoB,mDAAmD,0BAA0B,yBAAyB,wBAAwB,4BAA4B,GAAG,0BAA0B,sEAAsE,GAAG,6BAA6B,qCAAqC,wBAAwB,GAAG,qEAAqE,uDAAuD,mCAAmC,sFAAsF,eAAe,GAAG,qBAAqB;AACxkF;AACA,iEAAe,uBAAuB,EAAC;;;;;;;;;;;;;;;AC5EvC;AAC6G;AACjB;AAC5F,8BAA8B,mFAA2B,CAAC,4FAAqC;AAC/F;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,OAAO,qGAAqG,MAAM,YAAY,aAAa,OAAO,aAAa,MAAM,YAAY,OAAO,YAAY,YAAY,OAAO,aAAa,MAAM,UAAU,MAAM,aAAa,MAAM,UAAU,YAAY,WAAW,MAAM,aAAa,cAAc,aAAa,MAAM,YAAY,OAAO,YAAY,MAAM,YAAY,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,aAAa,OAAO,aAAa,MAAM,YAAY,aAAa,aAAa,aAAa,OAAO,aAAa,MAAM,YAAY,WAAW,YAAY,aAAa,OAAO,aAAa,MAAM,YAAY,yHAAyH,iEAAiE,6CAA6C,GAAG,sGAAsG,+BAA+B,GAAG,odAAod,sDAAsD,GAAG,qGAAqG,gBAAgB,GAAG,6GAA6G,iBAAiB,kCAAkC,iBAAiB,GAAG,yVAAyV,gCAAgC,GAAG,iLAAiL,kCAAkC,sBAAsB,wBAAwB,0BAA0B,6BAA6B,6BAA6B,oCAAoC,0BAA0B,mCAAmC,2CAA2C,+BAA+B,mDAAmD,yEAAyE,wDAAwD,mDAAmD,gDAAgD,uCAAuC,GAAG,+GAA+G,mCAAmC,sBAAsB,gCAAgC,gCAAgC,GAAG,uGAAuG,+BAA+B,iBAAiB,qCAAqC,0BAA0B,GAAG,qGAAqG,yBAAyB,GAAG,qBAAqB;AACluH;AACA,iEAAe,uBAAuB,EAAC;;;;;;;;ACjG1B;;AAEb;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,qDAAqD;AACrD;AACA;AACA,gDAAgD;AAChD;AACA;AACA,qFAAqF;AACrF;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB,iBAAiB;AACvC;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,qBAAqB;AAC1C;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV,sFAAsF,qBAAqB;AAC3G;AACA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV,iDAAiD,qBAAqB;AACtE;AACA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV,sDAAsD,qBAAqB;AAC3E;AACA;AACA;AACA;AACA;AACA;AACA;AACA,E;;;;;;;ACpFa;;AAEb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,E;;;;;;;ACzBa;;AAEb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uDAAuD,cAAc;AACrE;AACA;AACA;AACA;AACA,E;;;;;;;ACfa;;AAEb;AACA;AACA;AACA,kBAAkB,wBAAwB;AAC1C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB,iBAAiB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,4BAA4B;AAChD;AACA;AACA;AACA;AACA;AACA,qBAAqB,6BAA6B;AAClD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,E;;;;;;;ACnFa;;AAEb;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kC;;;;;;;ACjCa;;AAEb;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oC;;;;;;;ACTa;;AAEb;AACA;AACA,cAAc,KAAwC,GAAG,sBAAiB,GAAG,CAAI;AACjF;AACA;AACA;AACA;AACA,gD;;;;;;;ACTa;;AAEb;AACA;AACA;AACA;AACA,kDAAkD;AAClD;AACA;AACA,0CAA0C;AAC1C;AACA;AACA;AACA,iFAAiF;AACjF;AACA;AACA;AACA,aAAa;AACb;AACA;AACA,aAAa;AACb;AACA;AACA,aAAa;AACb;AACA;AACA;AACA,yDAAyD;AACzD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,kCAAkC;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,wB;;;;;;;AC5Da;;AAEb;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA,mC;;;;;;;;;;;;;;ACbA,iD;;;;;;;ACAA,kD;;;;;;;ACAA,kD;;;;;;UCAA;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;UAEA;UACA;;;;;WCzBA;WACA;WACA;WACA;WACA;WACA,iCAAiC,WAAW;WAC5C;WACA,E;;;;;WCPA;WACA;WACA;WACA;WACA,yCAAyC,wCAAwC;WACjF;WACA;WACA,E;;;;;WCPA,wF;;;;;WCAA;;WAEA;WACA;WACA;WACA;WACA;WACA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA,oB;;;;;WCrBA,mC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACCA,MAAkG;AAClG,MAAwF;AACxF,MAA+F;AAC/F,MAAkH;AAClH,MAA2G;AAC3G,MAA2G;AAC3G,MAA6G;AAC7G;AACA;;AAEA;;AAEA,4BAA4B,6BAAmB;AAC/C,wBAAwB,0CAAa;AACrC,iBAAiB,+BAAa;AAC9B,iBAAiB,uBAAM;AACvB,6BAA6B,8BAAkB;;AAE/C,aAAa,kCAAG,CAAC,2BAAO;;;;AAIuD;AAC/E,OAAO,0DAAe,2BAAO,IAAI,2BAAO,UAAU,2BAAO,mBAAmB,EAAC;;;ACxB7E;;AAEO;AACP;AACA;;AAEO;AACP;AACA;;AAEO;AACP;AACA;;AAEO;AACP;AACA;;;AChBA;;AAE8B;AACK;AACQ;AACb;AACI;AACF;;AAEhC,WAAW,sEAAK;AAChB,gBAAgB,2EAAU;AAC1B,cAAc,yEAAQ;AACtB,WAAW,0FAAK;;AAEhB;AACA;;AAEA;AACA;AACA,mBAAmB,yEAAQ;AAC3B,iBAAiB,yEAAQ;;AAEzB;;AAEO;AACP;AACA,qCAAqC;AACrC;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;AACJ,uBAAuB,WAAW,IAAI,OAAO;AAC7C;;AAEA;AACA,EAAE,GAAS,cAAc,QAAQ,IAAI,WAAW,IAAI,MAAM;AAC1D;AACA;AACA,IAAI,kEAAO;AACX,IAAI,kEAAO;AACX,IAAI,kEAAO;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,kEAAO,0EAA0E;AACtG,qBAAqB,kEAAO;AAC5B,GAAG;AACH;AACA,UAAU,UAAU;AACpB,IAAI,cAAc,0CAA0C,WAAW,IAAI,MAAM;AACjF;;AAEO;AACP,EAAE,GAAS,kBAAkB,QAAQ,QAAQ,WAAW,IAAI,MAAM;;AAElE;AACA;AACA;AACA;AACA;AACA,8BAA8B,QAAQ,gBAAgB,YAAY,EAAE,MAAM;AAC1E;AACA;AACA;AACA,IAAI,kEAAO;AACX,IAAI,kEAAO;AACX,IAAI,kEAAO;AACX;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,kEAAO;AAC/B;AACA;AACA;AACA,GAAG;AACH,QAAQ,UAAU;AAClB;;AAEA;AACA;AACA,sCAAsC;AACtC;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,GAAS;AACjB;AACA,OAAO;AACP;AACA;AACA;AACA,QAAQ,GAAS;AACjB;AACA,OAAO;AACP;AACA;AACA;AACA;;AAEA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEO;AACP;AACA;AACA;AACA;AACA;;AAEO;AACP;AACA;AACA;AACA;AACA;;AAEA;;AAEO;AACP;AACA;AACA;AACA;AACA;;AAEO;AACP;AACA,6BAA6B,WAAW;AACxC;AACA;AACA;AACA;AACA;;AAEO;AACP;AACA;AACA;AACA;AACA,MAAM,GAAS,mCAAmC,SAAS,KAAK,SAAS;AACzE;AACA;AACA;AACA,yBAAyB,cAAc;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO;AACP;AACA,6CAA6C;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,uEAAY;AACpC;AACA;AACA;AACA,UAAU;AACV,UAAU,KAAW,sBAAsB,OAAO,OAAO,OAAO,IAAI,IAAI;AACxE;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA,wCAAwC,sEAAK;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR,QAAQ,KAAW;AACnB;AACA;AACA;AACA,KAAK;AACL,MAAM,KAAW;AACjB;AACA;AACA,KAAK;AACL;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN,MAAM,KAAW;AACjB;AACA;AACA;AACA;;AAEA,UAAU,MAAM;AAChB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA,0BAA0B;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN,MAAM,KAAW;AACjB;AACA;AACA;AACA;AACA;;AAEA;AACA;;;;;;ACpUA,MAAkG;AAClG,MAAwF;AACxF,MAA+F;AAC/F,MAAkH;AAClH,MAA2G;AAC3G,MAA2G;AAC3G,MAA2G;AAC3G;AACA;;AAEA,IAAI,kBAAO;;AAEX,kBAAO,qBAAqB,6BAAmB;AAC/C,kBAAO,iBAAiB,0CAAa;AACrC,kBAAO,UAAU,+BAAa;AAC9B,kBAAO,UAAU,uBAAM;AACvB,kBAAO,sBAAsB,8BAAkB;;AAE/C,IAAI,iBAAM,GAAG,kCAAG,CAAC,yBAAO,EAAE,kBAAO;;;;AAI4C;AAC7E,OAAO,wDAAe,yBAAO,IAAI,yBAAO,UAAU,yBAAO,mBAAmB,EAAC;;;ACxB7C;AACF;AACK;AACH;;AAEhC,MAAM,aAAE,GAAG,0FAAK;AAChB,MAAM,aAAE,GAAG,sEAAK;AAChB;;AAEO;AACP;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA,sBAAsB,yBAAyB;AAC/C;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,KAAK;AACL;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;AACA;AACA,gBAAgB,yCAAyC;AACzD,GAAG;AACH;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;AACA;AACA;AACA,QAAQ,6CAA6C;AACrD,QAAQ;AACR;AACA,GAAG;AACH;;AAEA;;AAEA;AACA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEO;AACP,kBAAkB,2EAAU;AAC5B;;AAEO,SAAS,oBAAS;AACzB,uBAAuB,aAAE;AACzB,kBAAkB,aAAE;AACpB;AACA;AACA;AACO;AACP;AACA;AACA,uCAAuC,aAAE;AACzC,2BAA2B,aAAE,cAAc,aAAE;AAC7C;AACA,UAAU;AACV,UAAU,GAAS;AACnB;AACA;AACA,OAAO;AACP,MAAM,GAAS;AACf;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA,EAAE,GAAS;AACX,aAAa,aAAE,8BAA8B,aAAE;AAC/C;AACA,UAAU,aAAE;AACZ,UAAU,aAAE;AACZ,IAAI,GAAS;AACb,IAAI;AACJ,IAAI,KAAW;AACf;AACA;AACA;;AAEO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO;AACP;AACA,IAAI,aAAE,QAAQ,aAAE;AAChB,IAAI,aAAE,QAAQ,aAAE;AAChB,IAAI,aAAE,QAAQ,aAAE;AAChB;AACA;;AAEA;AACA;AACA,WAAW,aAAa;AACxB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEO;AACP,YAAY,aAAE;AACd,aAAa,aAAE;AACf;;AAEA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;;AClW8B;AACA;AACK;AACS;AACZ;AACoC;;AAEpE,MAAM,eAAE,GAAG,sEAAK;AAChB,MAAM,kBAAK,GAAG,yEAAQ;AACtB,MAAM,eAAE,GAAG,0FAAK;AAChB,gBAAgB,eAAE;;AAElB;AACA;AACO;AACP;AACA;AACA;AACA;AACA,GAAG;AACH;AACA,IAAI,eAAE;AACN;AACA;AACA;;AAEA;AACA;AACA;AACA,YAAY,WAAW;AACvB;AACO;AACP,QAAQ,eAAE;AACV,yBAAyB,eAAE,WAAW,eAAE;;AAExC,eAAe,kBAAK;AACpB,iBAAiB,eAAE;AACnB;AACA;AACA;;AAEA;AACA;AACA;AACA,IAAI,kEAAO,SAAS,eAAE;AACtB,IAAI,kEAAO,SAAS,eAAE;AACtB;AACA,IAAI,kEAAO,SAAS,eAAE;AACtB,IAAI,kEAAO,SAAS,eAAE;;AAEtB,IAAI,kEAAO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CO;AACP;AACA,2BAA2B,2EAAU;AACrC;;AAEA;AACA;AACA,MAAM,kEAAO,UAAU,iBAAE;AACzB;AACA;AACA;AACA,cAAc,iBAAE;AAChB,QAAQ;AACR,cAAc,iBAAE;AAChB;AACA,MAAM;AACN;AACA,MAAM,KAAW;AACjB;AACA;AACA;;AAEA;AACA,IAAI,iBAAE;AACN;AACA,QAAQ,KAAW;AACnB,QAAQ;AACR,sBAAsB,iBAAE;AACxB;AACA,UAAU,GAAS;AACnB;AACA,QAAQ,GAAS;AACjB,QAAQ,iBAAE,cAAc,iBAAE;AAC1B;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAM,IAAU;AAChB;AACA;AACA;AACA;AACA;AACA,kBAAkB,iBAAE;AACpB,MAAM;AACN;AACA,kBAAkB,iBAAE;AACpB;;AAEA;AACA,kBAAkB;AAClB;AACA,YAAY,iBAAE;AACd,WAAW,iBAAE,gBAAgB,iBAAE;AAC/B;AACA;AACA;AACA;AACA,IAAI,GAAS;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,iBAAE;AACN;AACA;AACA;AACA,OAAO;AACP;AACA;AACA,UAAU,KAAW;AACrB;AACA;AACA;AACA,QAAQ,GAAS;AACjB,QAAQ,iBAAE;AACV,QAAQ,iBAAE;AACV,oCAAoC,4BAA4B;AAChE;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA,cAAc,KAAW;AACzB;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA,kBAAkB,mEAAQ;AAC1B,MAAM,GAAS;AACf;AACA;AACA;AACA,qCAAqC;AACrC,kBAAkB,mEAAQ;AAC1B;AACA,0BAA0B;AAC1B;AACA;AACA,yBAAyB,iBAAE;AAC3B,UAAU;AACV,UAAU,KAAW;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,KAAW;AACrB;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,oBAAoB,kBAAkB;AACtC;AACA,MAAM,GAAS;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,UAAU,GAAS;AACnB;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI,2EAAU;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,0FAAK;AACX;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,SAAS;AACT,MAAM,2EAAU;AAChB;AACA;AACA;;AAEA;AACA,iBAAiB,iBAAE,eAAe,iBAAE;AACpC;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR,MAAM;AACN,MAAM,oBAAK;AACX;AACA;;AAEA;AACA;AACA,qBAAqB,iBAAE;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,mBAAmB,2EAAU;AAC7B;AACA,MAAM,yEAAQ;AACd;AACA;AACA,QAAQ;AACR;AACA;AACA,qBAAqB,iBAAE;AACvB,uBAAuB,iBAAE;AACzB;AACA;AACA;AACA,UAAU,WAAW;AACrB;AACA;AACA,kBAAkB,aAAa;AAC/B;AACA,YAAY,GAAS;AACrB,yCAAyC,iBAAE;AAC3C,YAAY,GAAS;AACrB,kBAAkB,iBAAE;AACpB,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,2EAAU;AACd;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,MAAM,yEAAQ,mBAAmB,iBAAE;AACnC;AACA;AACA;AACA,QAAQ,2EAAU;AAClB;AACA,MAAM;AACN,MAAM,GAAS;AACf;AACA;AACA;AACA;;AAEA;;AAEA,mBAAmB,iBAAE,qCAAqC,iBAAE;AAC5D;AACA;AACA;AACA,EAAE,2EAAU;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;AC7UA,MAAkG;AAClG,MAAwF;AACxF,MAA+F;AAC/F,MAAkH;AAClH,MAA2G;AAC3G,MAA2G;AAC3G,MAAgH;AAChH;AACA;;AAEA,IAAI,uBAAO;;AAEX,uBAAO,qBAAqB,6BAAmB;AAC/C,uBAAO,iBAAiB,0CAAa;AACrC,uBAAO,UAAU,+BAAa;AAC9B,uBAAO,UAAU,uBAAM;AACvB,uBAAO,sBAAsB,8BAAkB;;AAE/C,IAAI,sBAAM,GAAG,kCAAG,CAAC,8BAAO,EAAE,uBAAO;;;;AAIiD;AAClF,OAAO,6DAAe,8BAAO,IAAI,8BAAO,UAAU,8BAAO,mBAAmB,EAAC;;;ACxBM;AACrD;AACY;AACV;AAC4F;AAClE;;AAE1D,MAAM,uBAAE,GAAG,sEAAK;AAChB,MAAM,0BAAK,GAAG,yEAAQ;AACtB,MAAM,uBAAE,GAAG,0FAAK;AAChB,IAAI,wBAAG;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEO;AACP;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEO;AACP,EAAE,wBAAG;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,0BAAK;AACP;;AAEA;AACA,aAAa,6BAA6B;AAC1C;AACO;AACP,eAAe,uBAAE,YAAY,uBAAE;AAC/B,kBAAkB,wBAAG;AACrB;AACA;AACA;AACA,EAAE,2EAAU;;AAEZ,0CAA0C,wBAAG;AAC7C;AACA;AACA;;AAEA,WAAW;AACX;;AAEO;AACP;AACA,gBAAgB,uBAAE;AAClB;AACA,oBAAoB,gBAAgB;AACpC,MAAM;AACN;AACA,MAAM,WAAW;AACjB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,uBAAE;AACN;AACA,QAAQ,KAAW;AACnB;AACA;AACA,KAAK;AACL;;AAEA,UAAU,uBAAuB;;AAEjC;AACA,EAAE,2EAAU;AACZ;AACA;AACA,EAAE;;AAEK;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,uBAAE;AACR;AACA;AACA;AACA;AACA;AACA,UAAU,KAAW;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL;;AAEA,kBAAkB,8BAA8B;AAChD;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,IAAI;AACJ;;AAEO;AACP,kBAAkB,wBAAwB;AAC1C;AACA;AACA;AACA;AACA;AACA;;AAEO;AACP,EAAE,wBAAG;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,0BAAK;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAM,uBAAE,2BAA2B,uBAAE;AACrC;AACA;AACA;AACA;AACA,uBAAuB,uBAAE,WAAW,uBAAE;AACtC,sBAAsB,uBAAE,YAAY,uBAAE;AACtC;AACA,oBAAoB,uBAAE,QAAQ,uBAAE;AAChC,KAAK;AACL;AACA;AACA;AACA;AACA;;AAEO;AACP,qBAAqB,uBAAE,WAAW,uBAAE;AACpC;AACA,UAAU,uBAAE;AACZ,sBAAsB,uBAAE,YAAY,uBAAE;AACtC,UAAU,uBAAE;AACZ;AACA,IAAI;AACJ;AACA;AACA;;AAEA;AACO;AACP;AACA;AACA;AACA;AACA;AACA,QAAQ,uBAAE;AACV,cAAc,uBAAE,gBAAgB,uBAAE;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI,IAAU;AACd;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA,6DAA6D,uBAAE;AAC/D;AACA;AACA,2BAA2B,YAAY,CAAC,uBAAE;AAC1C;AACA,GAAG;AACH,aAAa,cAAc;AAC3B,kBAAkB,qBAAqB;AACvC;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA,qBAAqB,wBAAG;AACxB;AACA;AACA;AACA;AACA,IAAI,2EAAU;;AAEd;AACA,mBAAmB,wBAAG;AACtB;;AAEA;AACA,sBAAsB,wBAAG;AACzB;AACA;AACA,0BAA0B,wBAAG;AAC7B;AACA;AACA;;AAEA;AACA,iBAAiB,OAAO;;AAExB;AACA;AACA,wBAAwB,uBAAE,aAAa,uBAAE;AACzC;AACA,oBAAoB,wBAAG;AACvB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,IAAI,uBAAE;AACN;AACA,QAAQ,KAAW;AACnB;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA,oBAAoB,wBAAG;AACvB;;AAEA;AACA,oBAAoB,wBAAG;AACvB;AACA;;AAEA;;AAEA;AACA,qBAAqB,wBAAG;AACxB;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,EAAE,0BAAK;AACP;AACA,EAAE;;AAEK;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA,IAAI,QAAQ,cAAc,wBAAG;AAC7B;AACA;AACA,EAAE,uBAAE;AACJ;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,KAAW;AACjB,MAAM,QAAQ,cAAc,wBAAG;AAC/B;AACA;AACA;;AAEA;AACA,oBAAoB,wBAAG;AACvB;AACA,mBAAmB,2EAAU,UAAU,wBAAG;AAC1C;AACA;;AAEA,QAAQ,0FAAK;AACb;AACA,2BAA2B,2EAAU;AACrC,QAAQ,wBAAG;AACX;AACA;AACA;AACA;;AAEA,wBAAwB,uBAAE,aAAa,uBAAE;AACzC,UAAU,GAAS;AACnB;AACA;AACA,iCAAiC,uBAAE,WAAW,uBAAE;AAChD,gBAAgB,uBAAE;;AAElB;AACA;AACA;;AAEA;AACA,yBAAyB,sCAAe;AACxC;AACA;AACA;AACA,2BAA2B,oBAAS,CAAC,uBAAE;AACvC;AACA;AACA,kBAAkB,oBAAS,CAAC,uBAAE;AAC9B,2DAA2D,uBAAE,2BAA2B,uBAAE;AAC1F;AACA,aAAa;AACb,WAAW;;AAEX;AACA,gBAAgB,uBAAE;;AAElB;AACA,kBAAkB,iBAAiB;AACnC,YAAY;AACZ,YAAY,QAAQ,cAAc,wBAAG;AACrC;AACA;;AAEA;AACA,kBAAkB,eAAe,CAAC,uBAAE,sBAAsB,wBAAG;AAC7D,YAAY;AACZ;AACA,YAAY,QAAQ,cAAc,wBAAG;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;AACH;;AAEO;AACP;AACA;AACA,oBAAoB,8BAA8B;AAClD;AACA;AACA;AACA;;AAEO;AACP;AACA;AACA,kBAAkB,8BAA8B;AAChD;AACA,+BAA+B,OAAO;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,kBAAkB,kBAAkB;AACpC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,kBAAkB,uBAAE;AACpB;AACA,kBAAkB,oBAAoB;AACtC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO;AACP;AACA;;AAEA;AACA,YAAY,WAAW,QAAQ,kBAAkB;;AAEjD,QAAQ,0FAAK;AACb;AACA,QAAQ,2EAAU;AAClB,UAAU,wBAAG;AACb;AACA;AACA;AACA,kBAAkB,uBAAE;AACpB,YAAY,GAAS;AACrB,WAAW;AACX;AACA;AACA;AACA;;AAEA;AACO;AACP;AACA;AACA,UAAU,uBAAE;AACZ,IAAI;AACJ;AACA;AACA,yBAAyB,uBAAE,cAAc,uBAAE;AAC3C;AACA,QAAQ,uBAAE;AACV;;;AC7hBA;AAC8B;AACY;AACL;AACL;AAC4C;AACvB;AACT;;AAE5C,MAAM,yBAAE,GAAG,sEAAK;AAChB,MAAM,yBAAE,GAAG,0FAAK;;AAEhB;AACO,SAAS,sCAAe,kBAAkB,yBAAE;AACnD,8CAA8C,yBAAE;AAChD,6BAA6B,yBAAE;AAC/B,8CAA8C,iBAAiB;AAC/D;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,sDAAsD;AACtD;AACA;;AAEA;AACA;AACA,iCAAiC,yBAAE;AACnC,gCAAgC,yBAAE;AAClC;AACA,sCAAsC,yBAAE;AACxC;AACA;AACA;AACA,uCAAuC,yBAAE;AACzC,KAAK;AACL,aAAa,WAAW;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAkC,yBAAE;AACpC;AACA;AACA,MAA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;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA,oBAAoB;AACpB;AACA;AACA,iBAAiB;AACjB;AACA;AACA,WAAW;AACX,UAAU;AACV;AACA;AACA,2BAA2B,YAAE,KAAK,cAAI;AACtC,4BAA4B,YAAE,KAAK,cAAI;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8BAA8B,uBAAuB;AACrD;AACA,gCAAgC,wBAAwB;AACxD,gEAAgE;AAChE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,WAAW;AACX,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,YAAY,YAAE;AACd;AACA;AACA,gBAAgB,aAAG;AACnB;AACA,wBAAwB,YAAE;AAC1B,wBAAwB,YAAE;AAC1B,wBAAwB,YAAE;AAC1B;AACA,yBAAyB,YAAE;AAC3B;AACA;AACA;AACA,qBAAqB;AACrB;;AAEA;AACA;AACA;AACA;AACA,kBAAkB,aAAG;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC,0EAAe,CAAC,YAAE;AACvD;AACA;AACA;AACA;AACA,kBAAkB,aAAG;AACrB;AACA,qCAAqC,YAAE,YAAY,YAAE;AACrD,sCAAsC,YAAE,YAAY,YAAE;AACtD,kCAAkC,uBAAuB;AACzD;AACA,oCAAoC,wBAAwB;AAC5D;AACA;AACA;AACA,sBAAsB,aAAG;AACzB,sBAAsB,aAAG;AACzB,sBAAsB,aAAG;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB,GAAS;AAC3B,kBAAkB;AAClB,kBAAkB,aAAG;AACrB,kBAAkB,aAAG;AACrB,kBAAkB,aAAG;AACrB,kBAAkB,aAAG;AACrB;AACA;AACA;AACA;AACA,eAAe;AACf;AACA,gBAAgB,aAAG;AACnB;AACA;AACA,eAAe;AACf,WAAW;AACX,UAAU;;AAEV;AACA;AACA;AACA,UAAU,aAAG;AACb;AACA;AACA;AACA,cAAc,aAAG;AACjB,cAAc,aAAG;AACjB;AACA;AACA;AACA;AACA,sCAAsC,2EAAU;AAChD;AACA,kCAAkC,kCAAkC;AACpE;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA,gBAAgB;AAChB;AACA;AACA;AACA;AACA;AACA,cAAc,aAAG;AACjB;AACA,aAAa;AACb,WAAW;AACX;;AAEA;AACA;AACA;AACA,YAAY,aAAG;AACf,4BAA4B,0BAA0B;AACtD;AACA;AACA;AACA,YAAY,YAAE,YAAY,YAAE;AAC5B,kCAAkC,+CAA+C,YAAY,CAAC,YAAE,WAAW;AAC3G,YAAY,aAAG;AACf;AACA,4BAA4B,+BAA+B;AAC3D;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,aAAG;;AAEf;AACA,cAAc,2HAAgE;AAC9E;AACA;AACA,8BAA8B,+BAA+B;AAC7D;AACA;AACA;AACA,kBAAkB;AAClB,kBAAkB,aAAG;AACrB;AACA;AACA,oBAAoB,aAAG;AACvB,oBAAoB;AACpB,oBAAoB,aAAG;AACvB;AACA;AACA;AACA,cAAc,aAAG;AACjB,cAAc;AACd;AACA,WAAW;AACX,UAAU;;AAEV;AACA;AACA,0BAA0B,YAAE;AAC5B,YAAY,aAAG;;AAEf;AACA,wBAAwB,wBAAwB;AAChD;AACA,qBAAqB,YAAE,gBAAgB,YAAE;AACzC;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB;AACA;AACA;;AAEA;AACA,4BAA4B,6BAA6B;AACzD;AACA;AACA;AACA,4BAA4B,2BAA2B;AACvD;AACA;AACA;AACA;AACA,4BAA4B,wBAAwB;AACpD;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,aAAG;;AAEf,YAAY,aAAG;AACf,YAAY,aAAG;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;;AAEA;AACA;AACA;;AAEA;AACA;AACA,4BAA4B,YAAE;AAC9B;AACA,8BAA8B,0BAA0B;AACxD;AACA,kBAAkB,YAAE;AACpB;AACA;AACA,6BAA6B,0EAAe,CAAC,YAAE;AAC/C,cAAc,aAAG;AACjB;;AAEA,qBAAqB,YAAE;AACvB;AACA;AACA,eAAe;AACf,aAAa;AACb;AACA,cAAc,aAAG;AACjB;AACA,aAAa;AACb;AACA,cAAc,aAAG;AACjB,aAAa;AACb;;AAEA;AACA;;AAEA;AACA;AACA;AACA,2BAA2B,YAAE;AAC7B;AACA,8BAA8B,0BAA0B;AACxD;AACA,kBAAkB,YAAE;AACpB;AACA;AACA,6BAA6B,0EAAe,CAAC,YAAE;AAC/C,cAAc,aAAG;AACjB;;AAEA,qBAAqB,YAAE;AACvB;AACA;AACA,eAAe;AACf,aAAa;AACb;AACA,cAAc,aAAG;AACjB;AACA,aAAa;AACb;AACA,cAAc,aAAG;AACjB,aAAa;AACb;;AAEA;AACA,UAAU,aAAG;AACb;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,gCAAgC,YAAE,YAAY,YAAE;AAChD;AACA,8BAA8B,YAAE,QAAQ,YAAE;AAC1C,eAAe;AACf;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;;AAEA;AACA,QAAQ,aAAG;AACX,QAAQ,YAAE;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,aAAG;AACf,WAAW;AACX;AACA;AACA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,eAAE;AACZ,UAAU,eAAE;AACZ,UAAU,eAAE;AACZ,UAAU,eAAE;AACZ;AACA;AACA,gBAAgB,gBAAgB;AAChC,UAAU;AACV,UAAU,KAAW;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8BAA8B;AAC9B;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA,WAAW;AACX;AACA;AACA,WAAW;AACX;AACA;AACA,QAAQ,WAAW,eAAE;AACrB,uCAAuC;AACvC,QAAQ;AACR,QAAQ,KAAW;AACnB;AACA;;AAEA,eAAe,0FAAK;;AAEpB;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA,YAAY,KAAW;AACvB;AACA,WAAW;AACX;;AAEA;AACA,2BAA2B,kBAAK,OAAO,eAAE;;AAEzC;AACA;AACA;AACA;AACA,kBAAkB,kBAAK;AACvB,UAAU;AACV,uBAAuB,eAAE,8BAA8B,eAAE;AACzD;AACA;AACA;AACA;AACA;;AAEA,wCAAwC,eAAE;AAC1C;AACA,gCAAgC;;AAEhC;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA,kCAAkC,uBAAuB;AACzD,mCAAmC,oBAAoB;AACvD,+BAA+B,oBAAoB;AACnD,gCAAgC,iBAAiB;AACjD,8BAA8B,mBAAmB;AACjD,+BAA+B,gBAAgB;AAC/C;AACA;AACA;AACA;AACA;AACA,sBAAsB,QAAQ;AAC9B;AACA;;AAEA;AACA,gBAAgB,2CAA2C;AAC3D;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,qEAAqE;AACrE;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,gBAAgB,6BAA6B;AAC7C;AACA;;AAEA;AACA,gBAAgB,0BAA0B;AAC1C;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA,QAAQ,cAAc,2CAA2C,GAAS,gCAAgC;AAC1G;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,8CAA8C,sEAAK;AACnD;AACA;AACA;AACA;;AAEA;AACA,MAAM;AACN,IAAI;AACJ,CAAC,GAAC;;AAEF;AACA;AACA,UAAU,iEAAiE;AAC3E;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ,IAAI,GAAS;AACb;AACA,EAAE,GAAS;;AAEX,qBAAqB,2EAAU;AAC/B,wCAAwC,sEAAK;AAC7C;AACA;AACA;AACA,kBAAkB,YAAY;AAC9B,IAAI;AACJ,IAAI,GAAS;AACb;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,EAAE,WAAW;AACb;AACA;AACA,EAAE,qBAAqB;AACvB;AACA;AACA,EAAE,oBAAoB;AACtB,EAAE,YAAY;;AAEd;AACA,wCAAwC,8EAAa;AACrD;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA,UAAU,oDAAoD;AAC9D;AACA,EAAE,2EAAU;AACZ,qCAAqC,sEAAK;AAC1C;AACA;AACA;AACA;AACA;AACA,uBAAuB,cAAc;AACrC,QAAQ;AACR;AACA,QAAQ,WAAW;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,YAAY;AAClB;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA,UAAU,MAAM;AAChB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,WAAW;AACX;;AAEA;AACA;AACA,UAAU,mDAAmD;;AAE7D;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,EAAE,0FAAK;AACP;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,iBAAiB;AACrB;AACA;AACA;AACA;AACA,UAAU,gBAAgB;AAC1B;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU,MAAM;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI,qBAAqB;AACzB,GAAG;;AAEH;AACA;AACA;AACA;AACA,IAAI,qBAAqB;AACzB,GAAG;;AAEH,WAAW;AACX;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,oBAAoB;AAC1B;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA,QAAQ,eAAe;AACvB,0BAA0B,WAAW;AACrC;AACA;AACA;AACA,UAAU,qBAAqB;AAC/B,UAAU,YAAY;AACtB,SAAS;AACT,QAAQ;AACR;AACA;AACA;AACA;AACA,QAAQ,qBAAqB;AAC7B;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,oBAAoB;AAC5B;AACA,QAAQ,iBAAiB;AACzB;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,UAAU,KAAW;AACrB,UAAU,WAAW;AACrB;AACA;AACA;AACA;AACA;AACA,QAAQ,WAAW;AACnB;AACA;;AAEA;AACA;AACA;AACA,QAAQ,eAAe;AACvB,0BAA0B,WAAW;AACrC;AACA;AACA;AACA,UAAU,qBAAqB;AAC/B,UAAU,YAAY;AACtB,SAAS;AACT,OAAO;AACP;;AAEA;AACA;AACA;AACA,IAAI,kBAAkB;AACtB;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,IAAI;AACJ,IAAI,WAAW;AACf,IAAI,YAAY;AAChB,IAAI,GAAS;AACb,IAAI;;AAEJ,WAAW;AACX;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,iBAAiB;AACvB;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,uBAAuB,aAAa;AACpC,QAAQ;AACR;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,kBAAkB,uCAAuC,EAAE,aAAa;AACxE;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,qBAAqB;AACjC;AACA;AACA,YAAY,oBAAoB;AAChC;AACA;AACA,gBAAgB,KAAW;AAC3B,uBAAuB,WAAW;AAClC;AACA,cAAc,YAAY;AAC1B,aAAa;AACb,WAAW;AACX,UAAU,2EAAU,iCAAiC,wBAAwB;;AAE7E;AACA,YAAY,2EAAU;AACtB;AACA;AACA;AACA;AACA,sBAAsB,iBAAiB;AACvC;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,WAAW;AAC3B;AACA;AACA,gBAAgB,qBAAqB;AACrC;AACA,gBAAgB,YAAY;AAC5B;AACA;AACA;AACA;AACA;;AAEA;AACA,SAAS;AACT;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,0DAA0D,0BAA0B;AACpF;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,iBAAiB;AACvB;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,QAAQ,8EAAa;AACrB;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,KAAW;AACzB,cAAc,QAAQ;AACtB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,yEAAQ;AACd,oBAAoB,GAAS;AAC7B;AACA,UAAU,KAAW;AACrB,UAAU,QAAQ;AAClB,SAAS;AACT,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,iBAAiB;AACvB;AACA;AACA;AACA;AACA,QAAQ,mBAAS;AACjB,UAAU,eAAe;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,WAAW;AACvB;AACA;AACA,YAAY,qBAAqB;AACjC;AACA;AACA;AACA,KAAK;AACL,IAAI;;AAEJ;AACA;;AAE6F;AACJ","sources":["webpack://ContactsPane/webpack/universalModuleDefinition","webpack://ContactsPane/./src/styles/contactsPane.css","webpack://ContactsPane/./src/styles/contactsRDFFormsEnforced.css","webpack://ContactsPane/./src/styles/groupMembership.css","webpack://ContactsPane/./src/styles/individual.css","webpack://ContactsPane/./src/styles/localUtils.css","webpack://ContactsPane/./src/styles/mugshotGallery.css","webpack://ContactsPane/./src/styles/toolsPane.css","webpack://ContactsPane/./src/styles/utilities.css","webpack://ContactsPane/./src/styles/webidControl.css","webpack://ContactsPane/./node_modules/css-loader/dist/runtime/api.js","webpack://ContactsPane/./node_modules/css-loader/dist/runtime/getUrl.js","webpack://ContactsPane/./node_modules/css-loader/dist/runtime/sourceMaps.js","webpack://ContactsPane/./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js","webpack://ContactsPane/./node_modules/style-loader/dist/runtime/insertBySelector.js","webpack://ContactsPane/./node_modules/style-loader/dist/runtime/insertStyleElement.js","webpack://ContactsPane/./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js","webpack://ContactsPane/./node_modules/style-loader/dist/runtime/styleDomAPI.js","webpack://ContactsPane/./node_modules/style-loader/dist/runtime/styleTagTransform.js","webpack://ContactsPane/external umd {\"commonjs\":\"rdflib\",\"commonjs2\":\"rdflib\",\"amd\":\"rdflib\",\"root\":\"$rdf\"}","webpack://ContactsPane/external umd {\"commonjs\":\"solid-logic\",\"commonjs2\":\"solid-logic\",\"amd\":\"solid-logic\",\"root\":\"SolidLogic\"}","webpack://ContactsPane/external umd {\"commonjs\":\"solid-ui\",\"commonjs2\":\"solid-ui\",\"amd\":\"solid-ui\",\"root\":\"UI\"}","webpack://ContactsPane/webpack/bootstrap","webpack://ContactsPane/webpack/runtime/compat get default export","webpack://ContactsPane/webpack/runtime/define property getters","webpack://ContactsPane/webpack/runtime/hasOwnProperty shorthand","webpack://ContactsPane/webpack/runtime/jsonp chunk loading","webpack://ContactsPane/webpack/runtime/nonce","webpack://ContactsPane/./src/styles/webidControl.css?e193","webpack://ContactsPane/./src/debug.js","webpack://ContactsPane/./src/webidControl.js","webpack://ContactsPane/./src/styles/localUtils.css?6e73","webpack://ContactsPane/./src/localUtils.js","webpack://ContactsPane/./src/contactLogic.js","webpack://ContactsPane/./src/mintNewAddressBook.js","webpack://ContactsPane/./src/styles/mugshotGallery.css?feaa","webpack://ContactsPane/./src/mugshotGallery.js","webpack://ContactsPane/./src/styles/groupMembership.css?2a89","webpack://ContactsPane/./src/addressBookPresenter.js","webpack://ContactsPane/./src/groupMembershipControl.js","webpack://ContactsPane/./src/styles/individual.css?c2a6","webpack://ContactsPane/./src/styles/contactsRDFFormsEnforced.css?250c","webpack://ContactsPane/./src/rdfFormsHelper.js","webpack://ContactsPane/./src/individual.js","webpack://ContactsPane/./src/styles/toolsPane.css?78a3","webpack://ContactsPane/./src/toolsPane.js","webpack://ContactsPane/./src/styles/utilities.css?4cc3","webpack://ContactsPane/./src/styles/contactsPane.css?c6fd","webpack://ContactsPane/./src/contactsPane.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"solid-logic\"), require(\"solid-ui\"), require(\"rdflib\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"solid-logic\", \"solid-ui\", \"rdflib\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ContactsPane\"] = factory(require(\"solid-logic\"), require(\"solid-ui\"), require(\"rdflib\"));\n\telse\n\t\troot[\"ContactsPane\"] = factory(root[\"SolidLogic\"], root[\"UI\"], root[\"$rdf\"]);\n})(globalThis, (__WEBPACK_EXTERNAL_MODULE__941__, __WEBPACK_EXTERNAL_MODULE__104__, __WEBPACK_EXTERNAL_MODULE__53__) => {\nreturn ","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nimport ___CSS_LOADER_GET_URL_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/getUrl.js\";\nvar ___CSS_LOADER_URL_IMPORT_0___ = new URL(\"data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 fill=%27%23999%27 viewBox=%270 0 24 24%27 width=%2720%27 height=%2720%27%3E%3Cpath d=%27M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99c.41.41 1.09.41 1.5 0s.41-1.09 0-1.5l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z%27/%3E%3C/svg%3E\", import.meta.url);\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\nvar ___CSS_LOADER_URL_REPLACEMENT_0___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_0___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* Focus indicator for keyboard navigation */\n.contactPane table tr[tabindex=\"0\"]:focus {\n outline: var(--focus-ring-width) solid var(--color-primary);\n outline-offset: 2px;\n background: var(--color-info-bg);\n}\n/* contactsPane styles — extracted from inline styles in contactsPane.js */\n/* Uses CSS custom properties from the global stylesheet (dev-global.css / mashlib) */\n\n/* ── Layout: Three-column browser ────────────────────────────── */\n\n.contactPane .peopleSection .selected {\n background-color: var(--color-info-bg) !important;\n}\n\n.contactPane .detailSection,\n.contactPane .addressBookSection {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n flex: 1 1 0; /* allow it to grow but not force wrap */\n min-width: 300px;\n box-sizing: border-box;\n background: var(--color-section-bg);\n}\n\n.contactPane .detailsSectionContent {\n flex: 1 1 auto;\n min-height: 200px;\n padding: var(--spacing-lg);\n max-width: 900px;\n width: 100%;\n box-sizing: border-box;\n}\n\n.contactPane .detailsSectionContent--wide {\n max-width: 900px;\n}\n\n.contactPane .cardFooter {\n display: flex;\n flex-wrap: nowrap; /* keep buttons inline */\n align-items: center; /* vertical centering if varied heights */\n gap: var(--spacing-xs);\n padding-top: var(--spacing-md);\n margin-top: var(--spacing-md);\n}\n\n.contactPane .detailsSectionContent {\n margin: 0;\n}\n\n/* ── Contact type chooser ───────────────────────────────────── */\n\n.contactPane .contactTypeChooser {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-sm);\n max-width: 360px;\n}\n\n.contactPane .contactTypeChooser h3 {\n margin: 0 0 var(--spacing-xs) 0;\n font-size: var(--font-size-lg);\n}\n\n.contactPane .contactTypeSelect {\n height: var(--min-touch-target);\n border: 1px solid var(--color-border-pale);\n border-radius: var(--border-radius-base);\n padding: 0 var(--spacing-sm);\n font-size: var(--font-size-sm);\n background: var(--color-section-bg);\n}\n\n/* ── Search ──────────────────────────────────────────────────── */\n\n.contactPane .allGroupsButton {\n border-radius: var(--border-radius-full) !important;\n /* existing styles */\n}\n/* wrapper to position clear icon/button */\n.contactPane .searchDiv {\n position: relative;\n}\n\n.contactPane .searchInput {\n height: var(--min-touch-target);\n border: 1px solid var(--color-border-pale);\n background-color: var(--color-section-bg);\n background-image: url(${___CSS_LOADER_URL_REPLACEMENT_0___});\n background-repeat: no-repeat;\n background-position: 8px center;\n background-size: 20px 20px;\n border-radius: var(--border-radius-base);\n padding: 0 var(--spacing-sm) 0 34px;\n font-size: var(--font-size-base);\n width: 100%;\n box-sizing: border-box;\n}\n\n/* clear button inside search input */\n.contactPane .searchClearButton {\n position: absolute;\n right: var(--spacing-sm);\n top: 50%;\n transform: translateY(-50%);\n border: none;\n background: transparent;\n font-size: var(--font-size-base);\n line-height: 1;\n padding: 0;\n cursor: pointer;\n color: var(--color-text-muted);\n /* visibility is controlled via the generic \\`.hidden\\` utility class */\n display: block;\n}\n.contactPane .searchClearButton.hidden {\n display: none;\n}\n.contactPane .searchClearButton:hover {\n color: var(--color-text);\n}\n\n/* ── Contact toolbar (top-right link + delete) ──────────────── */\n\n.contactPane .contact-toolbar {\n display: flex;\n align-items: center;\n gap: var(--spacing-sm);\n padding: var(--spacing-xs) 0;\n}\n\n.contactPane .contact-toolbar a {\n margin: 0.3em;\n}\n\n.contactPane .contact-toolbar a img {\n width: 1.3em;\n height: 1em;\n margin: 0;\n}\n\n.contact-toolbar .deleteButton {\n margin-left: auto; /* keeps delete icon on the right */\n margin-right: 0.2em;\n width: 1em;\n height: 1em;\n float: none; /* important: prevents overlap behavior */\n}\n\n/* ── \"All\" groups button ─────────────────────────────────────── */\n\n.contactPane .allGroupsButton {\n margin-left: var(--spacing-md);\n font-size: var(--font-size-base);\n}\n\n.contactPane .allGroupsButton--loading {\n background-color: var(--color-primary);\n}\n\n.contactPane .allGroupsButton--active {\n background-color: var(--color-primary);\n color: var(--color-background);\n}\n\n.contactPane .allGroupsButton--loaded {\n background-color: var(--color-primary);\n}\n\n/* ── Selection & visibility states ───────────────────────────── */\n\n.contactPane .group-loading {\n}\n\n/* ── Mint new address book ───────────────────────────────────── */\n\n.contactPane .claimSuccess {\n font-size: var(--font-size-xl);\n}\n\n.contactPane {\n display: flex;\n flex-direction: column;\n min-height: 100vh;\n}\n\n.contactPane .addressBook-grid {\n display: flex;\n flex-wrap: nowrap; /* keep sections side-by-side */\n flex: 1;\n min-width: 50%;\n align-items: stretch;\n width: 100%;\n box-sizing: border-box;\n overflow-x: auto; /* allow horizontal scroll if needed */\n}\n\n@media ((min-width: 500px) and (max-width: 900px)) {\n .contactPane .addressBookSection {\n max-width: 900px;\n }\n .contactPane .addressBookSection section {\n max-width: 485px;\n }\n}\n\n.contactPane .contactPane--narrow .addressBook-grid {\n flex-direction: column !important;\n flex-wrap: wrap !important;\n}\n\n.contactPane .contactPane--narrow .addressBookSection,\n.contactPane .contactPane--narrow .detailSection {\n flex: 1 1 100% !important;\n max-width: 100% !important;\n min-width: 0 !important;\n width: 100% !important;\n}\n\n@media (max-width: 1000px) {\n /* Stack sidebar + details vertically on narrow screens */\n .contactPane {\n min-height: auto !important;\n }\n\n .contactPane .addressBook-grid {\n flex-direction: column !important;\n flex-wrap: nowrap !important;\n min-height: auto !important;\n height: auto !important;\n }\n\n .contactPane .addressBookSection,\n .contactPane .detailSection {\n order: initial !important;\n flex: none !important;\n width: 100% !important;\n max-width: 100% !important;\n min-width: 0 !important;\n }\n\n .contactPane .addressBookSection {\n max-height: 60vh !important;\n min-height: auto !important;\n overflow-y: auto !important;\n padding-bottom: var(--spacing-lg) !important;\n }\n\n .contactPane .detailSection {\n max-height: none !important;\n min-height: auto !important;\n overflow-y: visible !important;\n }\n\n .contactPane .detailsSectionContent {\n display: flex !important;\n flex-direction: column !important;\n justify-content: flex-start !important;\n align-items: stretch !important;\n min-height: auto !important;\n height: auto !important;\n overflow-y: visible !important;\n }\n\n .contactPane .detailSection > .detailsSectionContent {\n padding-top: var(--spacing-sm) !important;\n box-sizing: border-box !important;\n }\n\n /* Keep a normal mobile text scale while preserving comfortable touch targets */\n .contactPane,\n .contactPane * {\n font-size: 1.5rem !important;\n }\n\n .contactPane .actionButton,\n .contactPane .searchInput,\n .contactPane .flatButton,\n .contactPane .buttonSection button,\n .contactPane .groupButtonsList button {\n min-height: calc(var(--min-touch-target) + 0.5em) !important;\n font-size: 1.5rem !important;\n padding: 0.875em 1em !important;\n }\n\n .contactPane .group-membership-item .group-membership-toolbar > img.hoverControlHide, .contactPane .group-membership-item .group-membership-toolbar > [data-testid=\"deleteButtonWithCheck\"],\n .individualPane .hoverControl img.hoverControlHide, \n .individualPane .hoverControl [data-testid=\"deleteButtonWithCheck\"] {\n display: inline-flex !important;\n visibility: visible !important;\n opacity: 1 !important;\n }\n}\n\n\n/* Card Section Background */\n.contactPane .section-bg {\n background: var(--color-section-bg);\n padding: var(--spacing-md);\n box-sizing: border-box;\n border: none !important;\n border-radius: 0 !important;\n}\n\n/* Keep detail section content anchored at top */\n.contactPane .detailSection {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: stretch;\n}\n\n.contactPane .detailsSectionContent {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: stretch;\n}\n\n/* ── Button section: horizontal scrollable row ──────────────── */\n\n.contactPane .buttonSection {\n display: flex;\n flex-wrap: nowrap;\n align-items: center;\n padding: var(--spacing-sm);\n padding-bottom: 0;\n overflow-x: auto;\n overflow-y: hidden;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: thin;\n margin-bottom: 0;\n}\n\n.contactPane .buttonSection::-webkit-scrollbar {\n height: 6px;\n}\n\n.contactPane .buttonSection::-webkit-scrollbar-thumb {\n background: var(--color-border-pale);\n border-radius: var(--border-radius-base);\n}\n\n.contactPane .buttonSection::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.contactPane .buttonSection .selected {\n background: none !important;\n}\n\n.contactPane .groupButtonsList {\n display: flex;\n flex-wrap: nowrap;\n align-items: center;\n gap: var(--spacing-xs);\n list-style: none;\n}\n\n.contactPane .buttonSection .groupButtonsList {\n margin-left: var(--spacing-xs);\n margin-right: var(--spacing-xs);\n padding-left: 0;\n}\n\n.contactPane .groupButtonsList li {\n flex-shrink: 0;\n}\n\n.contactPane .groupButtonsList button {\n white-space: nowrap;\n flex-shrink: 0;\n min-width: max-content;\n margin-left: 0;\n}\n\n/* Groups list in details section — flexible 2-column grid */\n.contactPane .detailsSectionContent .groupButtonsList {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n gap: var(--spacing-sm);\n list-style: none;\n padding: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.contactPane .detailsSectionContent .groupButtonsList li {\n width: 100%;\n aspect-ratio: auto;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--spacing-xs);\n}\n\n.contactPane .detailsSectionContent .groupButtonsList button {\n width: 100%;\n height: auto;\n text-align: center;\n border-radius: var(--border-radius-base);\n word-wrap: break-word;\n overflow-wrap: break-word;\n}\n\n.contactPane .detailsSectionContent .groupButtonsList li > img.hoverControlHide,\n.contactPane .detailsSectionContent .groupButtonsList li > img[data-testid=\"deleteButtonWithCheck\"] {\n display: block;\n align-self: flex-end;\n float: none !important;\n margin: 0 !important;\n}\n\n@media (max-width: 599px) {\n .contactPane .detailsSectionContent .groupButtonsList {\n grid-template-columns: repeat(2, 1fr);\n gap: var(--spacing-xs);\n }\n\n .contactPane .detailsSectionContent .groupButtonsList button {\n font-size: var(--font-size-sm);\n border-radius: var(--border-radius-base);\n }\n}\n\n@media (min-width: 900px) {\n .contactPane .detailsSectionContent .groupButtonsList {\n grid-template-columns: repeat(3, 1fr);\n }\n}\n\n.contactPane .detailsSectionContent .newGroupBtn {\n width: 100%;\n box-sizing: border-box;\n margin-top: var(--spacing-sm);\n}\n\n.contactPane .detailsSectionContent h3 {\n font-size: var(--font-size-xl);\n margin-bottom: var(--spacing-sm);\n padding-left: 0;\n}\n\n/* Delete confirmation POPUP — centered overlay in details section */\n.contactPane .detailSection {\n position: relative;\n}\n\n.contactPane .webidControl div[style*=\"position: relative\"]:has(> div[style*=\"display: grid\"]) {\n position: static !important;\n}\n\n\n.contactPane .webidControl .personaRow--webid td > div[style*=\"position: relative\"] > div,\n.contactPane .detailsSectionContent .groupButtonsList li > div[style*=\"position: relative\"] > div,\n.contactPane .detailsSectionContent .contact-toolbar > div[style*=\"position: relative\"] > div {\n position: absolute !important;\n left: auto !important;\n z-index: 9999 !important;\n display: grid !important;\n pointer-events: auto !important;\n opacity: 1 !important;\n visibility: visible !important;\n padding: var(--spacing-btn) !important;\n min-width: 12em !important;\n background: var(--color-background) !important;\n border: var(--border-width-sm) solid var(--color-primary) !important;\n border-radius: var(--border-radius-base) !important;\n box-shadow: var(--box-shadow-popup) !important;\n grid-template-columns: auto auto !important;\n gap: var(--spacing-xxs) !important;\n}\n\n.contactPane .detailsSectionContent .contact-toolbar > div[style*=\"position: relative\"] > div > button:has(> img[src\\$=\".svg\"]),\n.contactPane .detailsSectionContent .group-membership-item .group-membership-toolbar > div[style*=\"position: relative\"] > div > button:has(> img[src\\$=\".svg\"]),\n.contactPane .webidControl .personaRow--webid td > div[style*=\"position: relative\"] > div > button:has(> img[src\\$=\".svg\"]) {\n background-color: transparent !important;\n}\n\n/* Selected state for All contacts button */\n.contactPane .allGroupsButton--selected {\n background-color: var(--color-primary);\n color: var(--color-background);\n}\n\n/* ── Header section ──────────────────────────────────────────── */\n\n.contactPane .headerSection {\n background: var(--color-background);\n padding: var(--spacing-sm);\n border-top-left-radius: var(--border-radius-full);\n border-top-right-radius: var(--border-radius-full);\n margin-bottom: 0;\n}\n\n.contactPane .headerSection header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 0;\n}\n\n.contactPane .headerSection h2 {\n margin-bottom: 0;\n}\n\n/* ── Dotted horizontal rule ─────────────────────────────────── */\n\n.contactPane .dottedHr {\n border: none;\n border-top: 1px dotted var(--color-text-muted);\n margin: 0;\n}\n\n/* ── Search section ─────────────────────────────────────────── */\n\n.contactPane .searchSection {\n padding: var(--spacing-sm);\n padding-bottom: 0;\n margin-bottom: 0;\n}\n\n/* ── People list section ────────────────────────────────────── */\n\n.contactPane .peopleSection {\n display: flex;\n background: var(--color-background);\n border-top: 1px dotted var(--color-text-muted);\n margin-bottom: 0;\n}\n\n.contactPane .peopleSection ul {\n list-style: none;\n padding: 0;\n margin: 0;\n width: 100%;\n max-height: 70vh;\n overflow-y: auto;\n}\n\n.contactPane .peopleSection li {\n border-top: 1px solid var(--color-border-pale);\n padding: var(--spacing-xs);\n}\n\n/* ── Person list item (addressBookPresenter) ─────────────────── */\n\n.contactPane .personLi-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.contactPane .personLi-avatar {\n width: 45px;\n height: 45px;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.contactPane .personLi-avatar .avatar-placeholder {\n width: 36px;\n height: 36px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.contactPane .personLi-avatar img {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n object-fit: cover;\n}\n\n.contactPane .personLi-info {\n flex: 1;\n margin-left: var(--spacing-sm);\n overflow: hidden;\n}\n\n.contactPane .personLi-name {\n font-weight: bold;\n font-size: var(--font-size-base);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.contactPane .personLi-arrow {\n margin-left: auto;\n display: flex;\n align-items: center;\n}\n\n.contactPane .personLi--error {\n opacity: 0.5;\n}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/contactsPane.css\"],\"names\":[],\"mappings\":\"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\",\"sourcesContent\":[\"/* Focus indicator for keyboard navigation */\\n.contactPane table tr[tabindex=\\\"0\\\"]:focus {\\n outline: var(--focus-ring-width) solid var(--color-primary);\\n outline-offset: 2px;\\n background: var(--color-info-bg);\\n}\\n/* contactsPane styles — extracted from inline styles in contactsPane.js */\\n/* Uses CSS custom properties from the global stylesheet (dev-global.css / mashlib) */\\n\\n/* ── Layout: Three-column browser ────────────────────────────── */\\n\\n.contactPane .peopleSection .selected {\\n background-color: var(--color-info-bg) !important;\\n}\\n\\n.contactPane .detailSection,\\n.contactPane .addressBookSection {\\n display: flex;\\n flex-direction: column;\\n align-items: stretch;\\n flex: 1 1 0; /* allow it to grow but not force wrap */\\n min-width: 300px;\\n box-sizing: border-box;\\n background: var(--color-section-bg);\\n}\\n\\n.contactPane .detailsSectionContent {\\n flex: 1 1 auto;\\n min-height: 200px;\\n padding: var(--spacing-lg);\\n max-width: 900px;\\n width: 100%;\\n box-sizing: border-box;\\n}\\n\\n.contactPane .detailsSectionContent--wide {\\n max-width: 900px;\\n}\\n\\n.contactPane .cardFooter {\\n display: flex;\\n flex-wrap: nowrap; /* keep buttons inline */\\n align-items: center; /* vertical centering if varied heights */\\n gap: var(--spacing-xs);\\n padding-top: var(--spacing-md);\\n margin-top: var(--spacing-md);\\n}\\n\\n.contactPane .detailsSectionContent {\\n margin: 0;\\n}\\n\\n/* ── Contact type chooser ───────────────────────────────────── */\\n\\n.contactPane .contactTypeChooser {\\n display: flex;\\n flex-direction: column;\\n gap: var(--spacing-sm);\\n max-width: 360px;\\n}\\n\\n.contactPane .contactTypeChooser h3 {\\n margin: 0 0 var(--spacing-xs) 0;\\n font-size: var(--font-size-lg);\\n}\\n\\n.contactPane .contactTypeSelect {\\n height: var(--min-touch-target);\\n border: 1px solid var(--color-border-pale);\\n border-radius: var(--border-radius-base);\\n padding: 0 var(--spacing-sm);\\n font-size: var(--font-size-sm);\\n background: var(--color-section-bg);\\n}\\n\\n/* ── Search ──────────────────────────────────────────────────── */\\n\\n.contactPane .allGroupsButton {\\n border-radius: var(--border-radius-full) !important;\\n /* existing styles */\\n}\\n/* wrapper to position clear icon/button */\\n.contactPane .searchDiv {\\n position: relative;\\n}\\n\\n.contactPane .searchInput {\\n height: var(--min-touch-target);\\n border: 1px solid var(--color-border-pale);\\n background-color: var(--color-section-bg);\\n background-image: url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23999' viewBox='0 0 24 24' width='20' height='20'%3E%3Cpath d='M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99c.41.41 1.09.41 1.5 0s.41-1.09 0-1.5l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z'/%3E%3C/svg%3E\\\");\\n background-repeat: no-repeat;\\n background-position: 8px center;\\n background-size: 20px 20px;\\n border-radius: var(--border-radius-base);\\n padding: 0 var(--spacing-sm) 0 34px;\\n font-size: var(--font-size-base);\\n width: 100%;\\n box-sizing: border-box;\\n}\\n\\n/* clear button inside search input */\\n.contactPane .searchClearButton {\\n position: absolute;\\n right: var(--spacing-sm);\\n top: 50%;\\n transform: translateY(-50%);\\n border: none;\\n background: transparent;\\n font-size: var(--font-size-base);\\n line-height: 1;\\n padding: 0;\\n cursor: pointer;\\n color: var(--color-text-muted);\\n /* visibility is controlled via the generic `.hidden` utility class */\\n display: block;\\n}\\n.contactPane .searchClearButton.hidden {\\n display: none;\\n}\\n.contactPane .searchClearButton:hover {\\n color: var(--color-text);\\n}\\n\\n/* ── Contact toolbar (top-right link + delete) ──────────────── */\\n\\n.contactPane .contact-toolbar {\\n display: flex;\\n align-items: center;\\n gap: var(--spacing-sm);\\n padding: var(--spacing-xs) 0;\\n}\\n\\n.contactPane .contact-toolbar a {\\n margin: 0.3em;\\n}\\n\\n.contactPane .contact-toolbar a img {\\n width: 1.3em;\\n height: 1em;\\n margin: 0;\\n}\\n\\n.contact-toolbar .deleteButton {\\n margin-left: auto; /* keeps delete icon on the right */\\n margin-right: 0.2em;\\n width: 1em;\\n height: 1em;\\n float: none; /* important: prevents overlap behavior */\\n}\\n\\n/* ── \\\"All\\\" groups button ─────────────────────────────────────── */\\n\\n.contactPane .allGroupsButton {\\n margin-left: var(--spacing-md);\\n font-size: var(--font-size-base);\\n}\\n\\n.contactPane .allGroupsButton--loading {\\n background-color: var(--color-primary);\\n}\\n\\n.contactPane .allGroupsButton--active {\\n background-color: var(--color-primary);\\n color: var(--color-background);\\n}\\n\\n.contactPane .allGroupsButton--loaded {\\n background-color: var(--color-primary);\\n}\\n\\n/* ── Selection & visibility states ───────────────────────────── */\\n\\n.contactPane .group-loading {\\n}\\n\\n/* ── Mint new address book ───────────────────────────────────── */\\n\\n.contactPane .claimSuccess {\\n font-size: var(--font-size-xl);\\n}\\n\\n.contactPane {\\n display: flex;\\n flex-direction: column;\\n min-height: 100vh;\\n}\\n\\n.contactPane .addressBook-grid {\\n display: flex;\\n flex-wrap: nowrap; /* keep sections side-by-side */\\n flex: 1;\\n min-width: 50%;\\n align-items: stretch;\\n width: 100%;\\n box-sizing: border-box;\\n overflow-x: auto; /* allow horizontal scroll if needed */\\n}\\n\\n@media ((min-width: 500px) and (max-width: 900px)) {\\n .contactPane .addressBookSection {\\n max-width: 900px;\\n }\\n .contactPane .addressBookSection section {\\n max-width: 485px;\\n }\\n}\\n\\n.contactPane .contactPane--narrow .addressBook-grid {\\n flex-direction: column !important;\\n flex-wrap: wrap !important;\\n}\\n\\n.contactPane .contactPane--narrow .addressBookSection,\\n.contactPane .contactPane--narrow .detailSection {\\n flex: 1 1 100% !important;\\n max-width: 100% !important;\\n min-width: 0 !important;\\n width: 100% !important;\\n}\\n\\n@media (max-width: 1000px) {\\n /* Stack sidebar + details vertically on narrow screens */\\n .contactPane {\\n min-height: auto !important;\\n }\\n\\n .contactPane .addressBook-grid {\\n flex-direction: column !important;\\n flex-wrap: nowrap !important;\\n min-height: auto !important;\\n height: auto !important;\\n }\\n\\n .contactPane .addressBookSection,\\n .contactPane .detailSection {\\n order: initial !important;\\n flex: none !important;\\n width: 100% !important;\\n max-width: 100% !important;\\n min-width: 0 !important;\\n }\\n\\n .contactPane .addressBookSection {\\n max-height: 60vh !important;\\n min-height: auto !important;\\n overflow-y: auto !important;\\n padding-bottom: var(--spacing-lg) !important;\\n }\\n\\n .contactPane .detailSection {\\n max-height: none !important;\\n min-height: auto !important;\\n overflow-y: visible !important;\\n }\\n\\n .contactPane .detailsSectionContent {\\n display: flex !important;\\n flex-direction: column !important;\\n justify-content: flex-start !important;\\n align-items: stretch !important;\\n min-height: auto !important;\\n height: auto !important;\\n overflow-y: visible !important;\\n }\\n\\n .contactPane .detailSection > .detailsSectionContent {\\n padding-top: var(--spacing-sm) !important;\\n box-sizing: border-box !important;\\n }\\n\\n /* Keep a normal mobile text scale while preserving comfortable touch targets */\\n .contactPane,\\n .contactPane * {\\n font-size: 1.5rem !important;\\n }\\n\\n .contactPane .actionButton,\\n .contactPane .searchInput,\\n .contactPane .flatButton,\\n .contactPane .buttonSection button,\\n .contactPane .groupButtonsList button {\\n min-height: calc(var(--min-touch-target) + 0.5em) !important;\\n font-size: 1.5rem !important;\\n padding: 0.875em 1em !important;\\n }\\n\\n .contactPane .group-membership-item .group-membership-toolbar > img.hoverControlHide, .contactPane .group-membership-item .group-membership-toolbar > [data-testid=\\\"deleteButtonWithCheck\\\"],\\n .individualPane .hoverControl img.hoverControlHide, \\n .individualPane .hoverControl [data-testid=\\\"deleteButtonWithCheck\\\"] {\\n display: inline-flex !important;\\n visibility: visible !important;\\n opacity: 1 !important;\\n }\\n}\\n\\n\\n/* Card Section Background */\\n.contactPane .section-bg {\\n background: var(--color-section-bg);\\n padding: var(--spacing-md);\\n box-sizing: border-box;\\n border: none !important;\\n border-radius: 0 !important;\\n}\\n\\n/* Keep detail section content anchored at top */\\n.contactPane .detailSection {\\n display: flex;\\n flex-direction: column;\\n justify-content: flex-start;\\n align-items: stretch;\\n}\\n\\n.contactPane .detailsSectionContent {\\n display: flex;\\n flex-direction: column;\\n justify-content: flex-start;\\n align-items: stretch;\\n}\\n\\n/* ── Button section: horizontal scrollable row ──────────────── */\\n\\n.contactPane .buttonSection {\\n display: flex;\\n flex-wrap: nowrap;\\n align-items: center;\\n padding: var(--spacing-sm);\\n padding-bottom: 0;\\n overflow-x: auto;\\n overflow-y: hidden;\\n -webkit-overflow-scrolling: touch;\\n scrollbar-width: thin;\\n margin-bottom: 0;\\n}\\n\\n.contactPane .buttonSection::-webkit-scrollbar {\\n height: 6px;\\n}\\n\\n.contactPane .buttonSection::-webkit-scrollbar-thumb {\\n background: var(--color-border-pale);\\n border-radius: var(--border-radius-base);\\n}\\n\\n.contactPane .buttonSection::-webkit-scrollbar-track {\\n background: transparent;\\n}\\n\\n.contactPane .buttonSection .selected {\\n background: none !important;\\n}\\n\\n.contactPane .groupButtonsList {\\n display: flex;\\n flex-wrap: nowrap;\\n align-items: center;\\n gap: var(--spacing-xs);\\n list-style: none;\\n}\\n\\n.contactPane .buttonSection .groupButtonsList {\\n margin-left: var(--spacing-xs);\\n margin-right: var(--spacing-xs);\\n padding-left: 0;\\n}\\n\\n.contactPane .groupButtonsList li {\\n flex-shrink: 0;\\n}\\n\\n.contactPane .groupButtonsList button {\\n white-space: nowrap;\\n flex-shrink: 0;\\n min-width: max-content;\\n margin-left: 0;\\n}\\n\\n/* Groups list in details section — flexible 2-column grid */\\n.contactPane .detailsSectionContent .groupButtonsList {\\n display: grid;\\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\\n gap: var(--spacing-sm);\\n list-style: none;\\n padding: 0;\\n width: 100%;\\n box-sizing: border-box;\\n}\\n\\n.contactPane .detailsSectionContent .groupButtonsList li {\\n width: 100%;\\n aspect-ratio: auto;\\n display: flex;\\n flex-direction: column;\\n align-items: stretch;\\n gap: var(--spacing-xs);\\n}\\n\\n.contactPane .detailsSectionContent .groupButtonsList button {\\n width: 100%;\\n height: auto;\\n text-align: center;\\n border-radius: var(--border-radius-base);\\n word-wrap: break-word;\\n overflow-wrap: break-word;\\n}\\n\\n.contactPane .detailsSectionContent .groupButtonsList li > img.hoverControlHide,\\n.contactPane .detailsSectionContent .groupButtonsList li > img[data-testid=\\\"deleteButtonWithCheck\\\"] {\\n display: block;\\n align-self: flex-end;\\n float: none !important;\\n margin: 0 !important;\\n}\\n\\n@media (max-width: 599px) {\\n .contactPane .detailsSectionContent .groupButtonsList {\\n grid-template-columns: repeat(2, 1fr);\\n gap: var(--spacing-xs);\\n }\\n\\n .contactPane .detailsSectionContent .groupButtonsList button {\\n font-size: var(--font-size-sm);\\n border-radius: var(--border-radius-base);\\n }\\n}\\n\\n@media (min-width: 900px) {\\n .contactPane .detailsSectionContent .groupButtonsList {\\n grid-template-columns: repeat(3, 1fr);\\n }\\n}\\n\\n.contactPane .detailsSectionContent .newGroupBtn {\\n width: 100%;\\n box-sizing: border-box;\\n margin-top: var(--spacing-sm);\\n}\\n\\n.contactPane .detailsSectionContent h3 {\\n font-size: var(--font-size-xl);\\n margin-bottom: var(--spacing-sm);\\n padding-left: 0;\\n}\\n\\n/* Delete confirmation POPUP — centered overlay in details section */\\n.contactPane .detailSection {\\n position: relative;\\n}\\n\\n.contactPane .webidControl div[style*=\\\"position: relative\\\"]:has(> div[style*=\\\"display: grid\\\"]) {\\n position: static !important;\\n}\\n\\n\\n.contactPane .webidControl .personaRow--webid td > div[style*=\\\"position: relative\\\"] > div,\\n.contactPane .detailsSectionContent .groupButtonsList li > div[style*=\\\"position: relative\\\"] > div,\\n.contactPane .detailsSectionContent .contact-toolbar > div[style*=\\\"position: relative\\\"] > div {\\n position: absolute !important;\\n left: auto !important;\\n z-index: 9999 !important;\\n display: grid !important;\\n pointer-events: auto !important;\\n opacity: 1 !important;\\n visibility: visible !important;\\n padding: var(--spacing-btn) !important;\\n min-width: 12em !important;\\n background: var(--color-background) !important;\\n border: var(--border-width-sm) solid var(--color-primary) !important;\\n border-radius: var(--border-radius-base) !important;\\n box-shadow: var(--box-shadow-popup) !important;\\n grid-template-columns: auto auto !important;\\n gap: var(--spacing-xxs) !important;\\n}\\n\\n.contactPane .detailsSectionContent .contact-toolbar > div[style*=\\\"position: relative\\\"] > div > button:has(> img[src$=\\\".svg\\\"]),\\n.contactPane .detailsSectionContent .group-membership-item .group-membership-toolbar > div[style*=\\\"position: relative\\\"] > div > button:has(> img[src$=\\\".svg\\\"]),\\n.contactPane .webidControl .personaRow--webid td > div[style*=\\\"position: relative\\\"] > div > button:has(> img[src$=\\\".svg\\\"]) {\\n background-color: transparent !important;\\n}\\n\\n/* Selected state for All contacts button */\\n.contactPane .allGroupsButton--selected {\\n background-color: var(--color-primary);\\n color: var(--color-background);\\n}\\n\\n/* ── Header section ──────────────────────────────────────────── */\\n\\n.contactPane .headerSection {\\n background: var(--color-background);\\n padding: var(--spacing-sm);\\n border-top-left-radius: var(--border-radius-full);\\n border-top-right-radius: var(--border-radius-full);\\n margin-bottom: 0;\\n}\\n\\n.contactPane .headerSection header {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n margin-bottom: 0;\\n}\\n\\n.contactPane .headerSection h2 {\\n margin-bottom: 0;\\n}\\n\\n/* ── Dotted horizontal rule ─────────────────────────────────── */\\n\\n.contactPane .dottedHr {\\n border: none;\\n border-top: 1px dotted var(--color-text-muted);\\n margin: 0;\\n}\\n\\n/* ── Search section ─────────────────────────────────────────── */\\n\\n.contactPane .searchSection {\\n padding: var(--spacing-sm);\\n padding-bottom: 0;\\n margin-bottom: 0;\\n}\\n\\n/* ── People list section ────────────────────────────────────── */\\n\\n.contactPane .peopleSection {\\n display: flex;\\n background: var(--color-background);\\n border-top: 1px dotted var(--color-text-muted);\\n margin-bottom: 0;\\n}\\n\\n.contactPane .peopleSection ul {\\n list-style: none;\\n padding: 0;\\n margin: 0;\\n width: 100%;\\n max-height: 70vh;\\n overflow-y: auto;\\n}\\n\\n.contactPane .peopleSection li {\\n border-top: 1px solid var(--color-border-pale);\\n padding: var(--spacing-xs);\\n}\\n\\n/* ── Person list item (addressBookPresenter) ─────────────────── */\\n\\n.contactPane .personLi-row {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n}\\n\\n.contactPane .personLi-avatar {\\n width: 45px;\\n height: 45px;\\n flex-shrink: 0;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n\\n.contactPane .personLi-avatar .avatar-placeholder {\\n width: 36px;\\n height: 36px;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n\\n.contactPane .personLi-avatar img {\\n width: 40px;\\n height: 40px;\\n border-radius: 50%;\\n object-fit: cover;\\n}\\n\\n.contactPane .personLi-info {\\n flex: 1;\\n margin-left: var(--spacing-sm);\\n overflow: hidden;\\n}\\n\\n.contactPane .personLi-name {\\n font-weight: bold;\\n font-size: var(--font-size-base);\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n.contactPane .personLi-arrow {\\n margin-left: auto;\\n display: flex;\\n align-items: center;\\n}\\n\\n.contactPane .personLi--error {\\n opacity: 0.5;\\n}\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* Solid-UI form */\n\n/* Vertically center autocomplete input in .formFieldValue */\n.individualPane .formFieldValue > div[style*=\"flex-direction: row\"],\n.contactPane .formFieldValue > div[style*=\"flex-direction: row\"] {\n align-items: center;\n display: flex;\n}\n\n.individualPane .formFieldValue input[data-testid=\"autocomplete-input\"],\n.contactPane .formFieldValue input[data-testid=\"autocomplete-input\"] {\n vertical-align: middle;\n}\n\n.individualPane .hoverControl,\n.contactPane .hoverControl {\n position: relative;\n}\n\n/* In contactPane, hover controls in table cells may contain a link + delete icon.\n Make the cell grow and keep the delete icon right-aligned (no overlap). */\n.contactPane td.hoverControl:has(> a) {\n width: auto !important;\n min-width: 4em !important;\n justify-content: space-between !important;\n}\n\n.contactPane td.hoverControl:has(> a) > a {\n flex: 1 1 auto;\n min-width: 0;\n overflow-wrap: anywhere;\n word-break: break-word;\n white-space: normal;\n}\n\n.individualPane .hoverControl:has(> img:first-child),\n.contactPane .hoverControl:has(> img:first-child) {\n background-color: transparent !important;\n border: none !important;\n margin: 0 !important;\n border-radius: 0 !important;\n padding: var(--spacing-btn) !important;\n min-height: var(--min-touch-target);\n min-width: var(--min-touch-target);\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.individualPane .hoverControl:has(> img:first-child) > span,\n.contactPane .hoverControl:has(> img:first-child) > span {\n display: inline-flex;\n align-items: center;\n margin-left: var(--spacing-xxs);\n}\n\n.individualPane div[style*=\"padding: 0.5em\"]:has(> img),\n.contactPane div[style*=\"padding: 0.5em\"]:has(> img) {\n display: inline-flex;\n align-items: center;\n}\n\n.individualPane div[style*=\"padding: 0.5em\"]:has(> img) > span,\n.contactPane div[style*=\"padding: 0.5em\"]:has(> img) > span {\n margin-left: var(--spacing-xxs);\n}\n\n.individualPane .hoverControl:has(> img:first-child):hover,\n.contactPane .hoverControl:has(> img:first-child):hover {\n background-color: var(--color-section-bg) !important;\n}\n\n.individualPane button:has(> img[src\\$=\".svg\"]),\n.contactPane button:has(> img[src\\$=\".svg\"]) {\n background-color: var(--color-section-bg) !important;\n border: none !important;\n margin: 0 !important;\n border-radius: 0 !important;\n box-shadow: none !important;\n transition: background-color 0.2s ease, box-shadow 0.2s ease;\n}\n\n/* Ensure certain icon images render at a consistent size and align nicely when adjacent. */\n.contactPane img[src\\$=\"red.svg\"],\n.contactPane img[src\\$=\"go-to-this.png\"],\n.individualPane img[src\\$=\"red.svg\"],\n.individualPane img[src\\$=\"go-to-this.png\"] {\n width: 1.2em !important;\n height: 1.2em !important;\n max-width: none !important;\n max-height: none !important;\n object-fit: contain;\n display: inline-block;\n vertical-align: middle;\n}\n\n/* If the SVG button is inside a statsLog wrapper, add pink background to the button only. */\n.individualPane .statsLog button:has(> img[src\\$=\".svg\"]),\n.contactPane .statsLog button:has(> img[src\\$=\".svg\"]) {\n background-color: var(--color-info-bg) !important;\n border: initial !important;\n margin: initial !important;\n border-radius: initial !important;\n}\n\n/* Hide the “Continue” icon button that Solid-UI sometimes renders below textareas. */\n.individualPane button:has(> img[title=\"Continue\"]),\n.contactPane button:has(> img[title=\"Continue\"]) {\n display: none !important;\n}\n\n.contactPane .detailSection .detailsSectionContent button:has(> img[title=\"Continue\"]),\n.contactPane .detailSection .detailsSectionContent img[title=\"Continue\"] {\n display: inline-flex !important;\n}\n\n.contactPane .detailSection .detailsSectionContent img[title=\"Continue\"] {\n width: 2em !important;\n height: 2em !important;\n}\n\n/* Allow “Continue” buttons inside contactFormContainer to be visible. */\n.individualPane .contactFormContainer button:has(> img[src\\$=\"noun_1180158.svg\"]),\n.contactPane .contactFormContainer button:has(> img[src\\$=\"noun_1180158.svg\"]),\n.individualPane .contactFormContainer button:has(> img[title=\"Continue\"]),\n.contactPane .contactFormContainer button:has(> img[title=\"Continue\"]) {\n display: inline-flex !important;\n}\n\n/* Exception: allow “Continue” buttons inside statsLog to remain visible. */\n.individualPane .statsLog button:has(> img[title=\"Continue\"]),\n.contactPane .statsLog button:has(> img[title=\"Continue\"]),\n.individualPane .webidControl button:has(> img[title=\"Continue\"]),\n.contactPane .webidControl button:has(> img[title=\"Continue\"]){\n display: inline-flex !important;\n}\n\n.individualPane button,\n.contactPane button {\n min-height: var(--min-touch-target);\n min-width: var(--min-touch-target);\n}\n\n.individualPane input:not([type=\"color\"]),\n.contactPane input:not([type=\"color\"]) {\n width: 99%;\n max-width: 99%;\n min-width: 0;\n box-sizing: border-box;\n font: inherit;\n color: var(--color-text);\n background-color: var(--color-card-bg) !important;\n border: 1px solid var(--color-border-pale);\n margin-left: 0 !important;\n margin-right: 0 !important;\n}\n\n.individualPane textarea,\n.contactPane textarea,\n.individualPane .formFieldValue textarea,\n.contactPane .formFieldValue textarea {\n appearance: none;\n -webkit-appearance: none;\n border-radius: var(--border-radius-sm) !important;\n border: var(--border-width-xthin) solid var(--color-border-accent) !important;\n width: 99%;\n max-width: 99%;\n box-sizing: border-box;\n font: inherit;\n color: var(--color-text);\n background-color: var(--color-card-bg) !important;\n margin: 0 !important;\n margin-top: var(--spacing-xs);\n margin-left: 0 !important;\n margin-right: 0 !important;\n padding: var(--spacing-xs) !important;\n}\n\n.individualPane select,\n.contactPane select {\n max-width: 99%;\n min-width: 0;\n box-sizing: border-box;\n font: inherit;\n color: var(--color-text);\n background-color: var(--color-card-bg) !important;\n border: 1px solid var(--color-border-pale);\n}\n\n.individualPane input[type=\"date\"],\n.contactPane input[type=\"date\"],\n.individualPane input[type=\"month\"],\n.contactPane input[type=\"month\"],\n.individualPane input[type=\"week\"],\n.contactPane input[type=\"week\"],\n.individualPane input[type=\"time\"],\n.contactPane input[type=\"time\"],\n.individualPane input[type=\"datetime-local\"],\n.contactPane input[type=\"datetime-local\"] {\n min-height: var(--min-touch-target);\n}\n\n.individualPane .hoverControl:has(> img:first-child):focus-visible,\n.contactPane .hoverControl:has(> img:first-child):focus-visible,\n.individualPane button:focus-visible,\n.contactPane button:focus-visible,\n.individualPane input:not([type=\"color\"]):focus-visible,\n.contactPane input:not([type=\"color\"]):focus-visible,\n.individualPane textarea:focus-visible,\n.contactPane textarea:focus-visible,\n.individualPane select:focus-visible,\n.contactPane select:focus-visible {\n outline: var(--focus-ring-width) solid var(--color-primary) !important;\n outline-offset: 2px;\n box-shadow: 0 0 0 1px var(--color-background);\n}\n\n.individualPane input[type=\"url\"],\n.contactPane input[type=\"url\"] {\n width: 99%;\n}\n\n.individualPane .formFieldValue,\n.contactPane .formFieldValue {\n min-width: 0;\n margin-bottom: var(--spacing-sm);\n}\n\n.individualPane .formFieldValue table,\n.contactPane .formFieldValue table {\n margin: 0 !important;\n padding: 0 !important;\n}\n\n.individualPane .formFieldValue td,\n.contactPane .formFieldValue td {\n padding: 0 !important;\n vertical-align: middle;\n}\n\n.individualPane .formFieldValue table[data-testid=\"autocomplete-table\"],\n.contactPane .formFieldValue table[data-testid=\"autocomplete-table\"] {\n height: 100%;\n}\n\n.individualPane .formFieldValue input:not([type=\"color\"]),\n.contactPane .formFieldValue input:not([type=\"color\"]),\n.individualPane .formFieldValue textarea,\n.contactPane .formFieldValue textarea {\n width: 99% !important;\n max-width: 99%;\n}\n\n/* Email and phone value inputs: do not stretch full width */\n.individualPane .formFieldName:has(a[href=\"http://www.w3.org/2006/vcard/ns#value\"]) + .formFieldValue input:not([type=\"color\"]),\n.contactPane .formFieldName:has(a[href=\"http://www.w3.org/2006/vcard/ns#value\"]) + .formFieldValue input:not([type=\"color\"]) {\n width: 98% !important;\n max-width: 98%;\n}\n\n.individualPane .formFieldValue select,\n.contactPane .formFieldValue select {\n width: 99%;\n display: inline-block;\n max-width: none !important;\n}\n\n.individualPane select#formSelect,\n.contactPane select#formSelect {\n width: 99%;\n max-width: 98%;\n box-sizing: border-box;\n margin-left: 0 !important;\n margin-right: 0 !important;\n}\n\n.individualPane span select,\n.contactPane span select {\n max-width: 96% !important;\n box-sizing: border-box;\n margin: 0 !important;\n}\n\n.individualPane .formFieldValue span select,\n.contactPane .formFieldValue span select {\n margin-left: 0 !important;\n margin-right: 0 !important;\n}\n\n/* Remove border/padding from the first wrapper div (and its first child wrapper). */\n.individualPane > div:first-of-type,\n.contactPane > div:first-of-type,\n.individualPane > div:first-of-type > div:first-of-type,\n.contactPane > div:first-of-type > div:first-of-type {\n border: none !important;\n padding: 0 !important;\n}\n\n/* In contactPane, remove border/padding from all direct child divs. */\n.individualPane > div,\n.contactPane > div {\n border: none !important;\n padding: 0 !important;\n}\n\n/* Align schema.org, solid terms, FOAF, vCard, and org field labels with their input values. */\n.individualPane :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue),\n.contactPane :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue) {\n display: flex;\n align-items: baseline;\n margin-bottom: var(--spacing-sm);\n}\n\n/* for the Resume inside corporation choice */\n/* Add space between classifierBox label and select box */\n.individualPane .choiceBox .classifierBox-label,\n.contactPane .choiceBox .classifierBox-label {\n margin-right: 0;\n padding-left: var(--spacing-xxs);\n}\n\n.individualPane .choiceBox .choiceBox-selectBox select,\n.contactPane .choiceBox .choiceBox-selectBox select {\n margin-left: 2.1em !important;\n}\n\n/* for the Resume orga details */\n/* Add space between classifierBox label and select box */\n.individualPane .classifierBox .classifierBox-label,\n.contactPane .classifierBox .classifierBox-label {\n margin-right: 0;\n padding-left: var(--spacing-xxs);\n width: 8em;\n padding: var(--spacing-xxs);\n vertical-align: middle;\n}\n\n.individualPane .classifierBox .classifierBox-selectBox,\n.contactPane .classifierBox .classifierBox-selectBox {\n margin-left: 0 !important;\n}\n\n.individualPane .classifierBox .classifierBox-selectBox select,\n.contactPane .classifierBox .classifierBox-selectBox select {\n margin-left: 0 !important;\n}\n\n.individualPane .formFieldValue > span > select,\n.contactPane .formFieldValue > span > select {\n margin-left: 0 !important;\n}\n\n.individualPane :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue) > .formFieldValue,\n.contactPane :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue) > .formFieldValue {\n margin-bottom: 0;\n}\n\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://schema.org/\"]),\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://schema.org/\"]),\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/ns/solid/terms#\"]),\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/ns/solid/terms#\"]),\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://xmlns.com/foaf/0.1/\"]),\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://xmlns.com/foaf/0.1/\"]),\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/2006/vcard/ns\"]),\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/2006/vcard/ns\"]),\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/ns/org#\"]),\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/ns/org#\"]) {\n display: inline-flex;\n align-items: center;\n vertical-align: middle;\n}\n\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://schema.org/\"]) + .formFieldValue,\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://schema.org/\"]) + .formFieldValue,\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/ns/solid/terms#\"]) + .formFieldValue,\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/ns/solid/terms#\"]) + .formFieldValue,\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://xmlns.com/foaf/0.1/\"]) + .formFieldValue,\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://xmlns.com/foaf/0.1/\"]) + .formFieldValue,\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/2006/vcard/ns\"]) + .formFieldValue,\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/2006/vcard/ns\"]) + .formFieldValue,\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/ns/org#\"]) + .formFieldValue,\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/ns/org#\"]) + .formFieldValue {\n display: inline-flex;\n align-items: center;\n vertical-align: middle;\n flex: 1;\n min-width: 0;\n}\n\n/* Center textarea label vertically in flex rows. */\n.individualPane div[style*=\"display: flex\"][style*=\"flex-direction: row\"]:has(textarea),\n.contactPane div[style*=\"display: flex\"][style*=\"flex-direction: row\"]:has(textarea) {\n align-items: flex-start;\n}\n\n.individualPane div[style*=\"display: flex\"][style*=\"flex-direction: row\"]:has(textarea) > div:has(> a),\n.contactPane div[style*=\"display: flex\"][style*=\"flex-direction: row\"]:has(textarea) > div:has(> a) {\n padding-left: var(--spacing-xs);\n padding-top: var(--spacing-sm);\n}\n\n/* Keep autocomplete/table-based fields (e.g. Occupation) aligned to label text baseline. */\n.individualPane :not(.choiceBox):has(> .formFieldValue input[data-testid=\"autocomplete-input\"]),\n.contactPane :not(.choiceBox):has(> .formFieldValue input[data-testid=\"autocomplete-input\"]) {\n align-items: flex-start;\n}\n\n.individualPane :not(.choiceBox):has(> .formFieldValue input[data-testid=\"autocomplete-input\"]) > .formFieldName,\n.contactPane :not(.choiceBox):has(> .formFieldValue input[data-testid=\"autocomplete-input\"]) > .formFieldName {\n padding-top: var(--spacing-xs) !important;\n}\n\n.individualPane .formFieldValue:has(input[data-testid=\"autocomplete-input\"]),\n.contactPane .formFieldValue:has(input[data-testid=\"autocomplete-input\"]) {\n align-self: flex-start;\n}\n\n.individualPane .formFieldValue table[data-testid=\"autocomplete-table\"],\n.contactPane .formFieldValue table[data-testid=\"autocomplete-table\"],\n.individualPane .formFieldValue input[data-testid=\"autocomplete-input\"],\n.contactPane .formFieldValue input[data-testid=\"autocomplete-input\"] {\n margin: 0 !important;\n}\n\n.individualPane .formFieldValue table[data-testid=\"autocomplete-table\"],\n.contactPane .formFieldValue table[data-testid=\"autocomplete-table\"] {\n vertical-align: baseline;\n}\n\n.individualPane input:disabled,\n.contactPane input:disabled,\n.individualPane textarea:disabled,\n.contactPane textarea:disabled,\n.individualPane select:disabled,\n.contactPane select:disabled,\n.individualPane input[readonly],\n.contactPane input[readonly],\n.individualPane textarea[readonly],\n.contactPane textarea[readonly],\n.individualPane input:read-only,\n.contactPane input:read-only,\n.individualPane textarea:read-only,\n.contactPane textarea:read-only {\n background-color: var(--color-background) !important;\n cursor: not-allowed;\n opacity: var(--opacity-input-disabled);\n border: var(--border-width-xthin) solid var(--color-background) !important;\n}\n\n.contactPane .webidControl table td div.contactPane.namedPane {\n border: none !important;\n}\n\n/* ------------------------------------------------------------------ */\n/* inline popup used for small confirmation flows (like the new confirmDialog) */\n/* apply the class \\`rdf-inline-modal\\` on the outer wrapper and give the\n inner box the class \\`popup\\` instead of using the old inline styles. */\n\n/* selectors that match the old inline-styled markup when no classes can be added */\n\n/* Delete pop up */\n/* Remove the intermediate positioned ancestor so the popup anchors to .hoverControl instead */\n.individualPane div[style*=\"position: relative\"]:has(> div[style*=\"display: grid\"]) {\n position: static !important;\n}\n\n.individualPane div[style*=\"position: relative\"] > div[style*=\"display: grid\"] {\n /* override inline values with theme variables */\n position: absolute !important;\n top: 0 !important;\n right: 0 !important;\n left: auto !important;\n z-index: 9999 !important;\n display: grid !important;\n pointer-events: auto !important;\n opacity: 1 !important;\n visibility: visible !important;\n padding: var(--spacing-btn) !important;\n background: var(--color-background) !important;\n border: var(--border-width-sm) solid var(--color-primary) !important;\n border-radius: var(--border-radius-base) !important;\n box-shadow: var(--box-shadow-popup) !important;\n grid-template-columns: auto auto !important;\n gap: var(--spacing-xxs) !important;\n}\n\n.individualPane .hoverControl img.hoverControlHide,\n.individualPane .hoverControl [data-testid=\"deleteButtonWithCheck\"] {\n position: absolute !important;\n right: var(--spacing-xxxs) !important;\n width: 1.5em !important;\n height: 1.5em !important;\n display: none !important;\n align-items: center;\n justify-content: center;\n margin: 0 !important;\n float: none !important;\n z-index: 2 !important;\n}\n\n/* Show delete icon only on hover */\n.individualPane .hoverControl:hover img.hoverControlHide,\n.individualPane .hoverControl:hover [data-testid=\"deleteButtonWithCheck\"] {\n display: inline-flex !important;\n}\n\n/* If the hoverControl has exactly one div + the delete icon, keep the icon vertically centered but right-aligned */\n.individualPane .hoverControl:has(> div:nth-child(1):nth-last-child(2)):hover > img.hoverControlHide,\n.individualPane .hoverControl:has(> div:nth-child(1):nth-last-child(2)):hover > [data-testid=\"deleteButtonWithCheck\"] {\n top: 50% !important;\n right: var(--spacing-xxxs) !important;\n left: auto !important;\n transform: translateY(-50%) !important;\n}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/contactsRDFFormsEnforced.css\"],\"names\":[],\"mappings\":\"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\",\"sourcesContent\":[\"/* Solid-UI form */\\n\\n/* Vertically center autocomplete input in .formFieldValue */\\n.individualPane .formFieldValue > div[style*=\\\"flex-direction: row\\\"],\\n.contactPane .formFieldValue > div[style*=\\\"flex-direction: row\\\"] {\\n align-items: center;\\n display: flex;\\n}\\n\\n.individualPane .formFieldValue input[data-testid=\\\"autocomplete-input\\\"],\\n.contactPane .formFieldValue input[data-testid=\\\"autocomplete-input\\\"] {\\n vertical-align: middle;\\n}\\n\\n.individualPane .hoverControl,\\n.contactPane .hoverControl {\\n position: relative;\\n}\\n\\n/* In contactPane, hover controls in table cells may contain a link + delete icon.\\n Make the cell grow and keep the delete icon right-aligned (no overlap). */\\n.contactPane td.hoverControl:has(> a) {\\n width: auto !important;\\n min-width: 4em !important;\\n justify-content: space-between !important;\\n}\\n\\n.contactPane td.hoverControl:has(> a) > a {\\n flex: 1 1 auto;\\n min-width: 0;\\n overflow-wrap: anywhere;\\n word-break: break-word;\\n white-space: normal;\\n}\\n\\n.individualPane .hoverControl:has(> img:first-child),\\n.contactPane .hoverControl:has(> img:first-child) {\\n background-color: transparent !important;\\n border: none !important;\\n margin: 0 !important;\\n border-radius: 0 !important;\\n padding: var(--spacing-btn) !important;\\n min-height: var(--min-touch-target);\\n min-width: var(--min-touch-target);\\n cursor: pointer;\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n}\\n\\n.individualPane .hoverControl:has(> img:first-child) > span,\\n.contactPane .hoverControl:has(> img:first-child) > span {\\n display: inline-flex;\\n align-items: center;\\n margin-left: var(--spacing-xxs);\\n}\\n\\n.individualPane div[style*=\\\"padding: 0.5em\\\"]:has(> img),\\n.contactPane div[style*=\\\"padding: 0.5em\\\"]:has(> img) {\\n display: inline-flex;\\n align-items: center;\\n}\\n\\n.individualPane div[style*=\\\"padding: 0.5em\\\"]:has(> img) > span,\\n.contactPane div[style*=\\\"padding: 0.5em\\\"]:has(> img) > span {\\n margin-left: var(--spacing-xxs);\\n}\\n\\n.individualPane .hoverControl:has(> img:first-child):hover,\\n.contactPane .hoverControl:has(> img:first-child):hover {\\n background-color: var(--color-section-bg) !important;\\n}\\n\\n.individualPane button:has(> img[src$=\\\".svg\\\"]),\\n.contactPane button:has(> img[src$=\\\".svg\\\"]) {\\n background-color: var(--color-section-bg) !important;\\n border: none !important;\\n margin: 0 !important;\\n border-radius: 0 !important;\\n box-shadow: none !important;\\n transition: background-color 0.2s ease, box-shadow 0.2s ease;\\n}\\n\\n/* Ensure certain icon images render at a consistent size and align nicely when adjacent. */\\n.contactPane img[src$=\\\"red.svg\\\"],\\n.contactPane img[src$=\\\"go-to-this.png\\\"],\\n.individualPane img[src$=\\\"red.svg\\\"],\\n.individualPane img[src$=\\\"go-to-this.png\\\"] {\\n width: 1.2em !important;\\n height: 1.2em !important;\\n max-width: none !important;\\n max-height: none !important;\\n object-fit: contain;\\n display: inline-block;\\n vertical-align: middle;\\n}\\n\\n/* If the SVG button is inside a statsLog wrapper, add pink background to the button only. */\\n.individualPane .statsLog button:has(> img[src$=\\\".svg\\\"]),\\n.contactPane .statsLog button:has(> img[src$=\\\".svg\\\"]) {\\n background-color: var(--color-info-bg) !important;\\n border: initial !important;\\n margin: initial !important;\\n border-radius: initial !important;\\n}\\n\\n/* Hide the “Continue” icon button that Solid-UI sometimes renders below textareas. */\\n.individualPane button:has(> img[title=\\\"Continue\\\"]),\\n.contactPane button:has(> img[title=\\\"Continue\\\"]) {\\n display: none !important;\\n}\\n\\n.contactPane .detailSection .detailsSectionContent button:has(> img[title=\\\"Continue\\\"]),\\n.contactPane .detailSection .detailsSectionContent img[title=\\\"Continue\\\"] {\\n display: inline-flex !important;\\n}\\n\\n.contactPane .detailSection .detailsSectionContent img[title=\\\"Continue\\\"] {\\n width: 2em !important;\\n height: 2em !important;\\n}\\n\\n/* Allow “Continue” buttons inside contactFormContainer to be visible. */\\n.individualPane .contactFormContainer button:has(> img[src$=\\\"noun_1180158.svg\\\"]),\\n.contactPane .contactFormContainer button:has(> img[src$=\\\"noun_1180158.svg\\\"]),\\n.individualPane .contactFormContainer button:has(> img[title=\\\"Continue\\\"]),\\n.contactPane .contactFormContainer button:has(> img[title=\\\"Continue\\\"]) {\\n display: inline-flex !important;\\n}\\n\\n/* Exception: allow “Continue” buttons inside statsLog to remain visible. */\\n.individualPane .statsLog button:has(> img[title=\\\"Continue\\\"]),\\n.contactPane .statsLog button:has(> img[title=\\\"Continue\\\"]),\\n.individualPane .webidControl button:has(> img[title=\\\"Continue\\\"]),\\n.contactPane .webidControl button:has(> img[title=\\\"Continue\\\"]){\\n display: inline-flex !important;\\n}\\n\\n.individualPane button,\\n.contactPane button {\\n min-height: var(--min-touch-target);\\n min-width: var(--min-touch-target);\\n}\\n\\n.individualPane input:not([type=\\\"color\\\"]),\\n.contactPane input:not([type=\\\"color\\\"]) {\\n width: 99%;\\n max-width: 99%;\\n min-width: 0;\\n box-sizing: border-box;\\n font: inherit;\\n color: var(--color-text);\\n background-color: var(--color-card-bg) !important;\\n border: 1px solid var(--color-border-pale);\\n margin-left: 0 !important;\\n margin-right: 0 !important;\\n}\\n\\n.individualPane textarea,\\n.contactPane textarea,\\n.individualPane .formFieldValue textarea,\\n.contactPane .formFieldValue textarea {\\n appearance: none;\\n -webkit-appearance: none;\\n border-radius: var(--border-radius-sm) !important;\\n border: var(--border-width-xthin) solid var(--color-border-accent) !important;\\n width: 99%;\\n max-width: 99%;\\n box-sizing: border-box;\\n font: inherit;\\n color: var(--color-text);\\n background-color: var(--color-card-bg) !important;\\n margin: 0 !important;\\n margin-top: var(--spacing-xs);\\n margin-left: 0 !important;\\n margin-right: 0 !important;\\n padding: var(--spacing-xs) !important;\\n}\\n\\n.individualPane select,\\n.contactPane select {\\n max-width: 99%;\\n min-width: 0;\\n box-sizing: border-box;\\n font: inherit;\\n color: var(--color-text);\\n background-color: var(--color-card-bg) !important;\\n border: 1px solid var(--color-border-pale);\\n}\\n\\n.individualPane input[type=\\\"date\\\"],\\n.contactPane input[type=\\\"date\\\"],\\n.individualPane input[type=\\\"month\\\"],\\n.contactPane input[type=\\\"month\\\"],\\n.individualPane input[type=\\\"week\\\"],\\n.contactPane input[type=\\\"week\\\"],\\n.individualPane input[type=\\\"time\\\"],\\n.contactPane input[type=\\\"time\\\"],\\n.individualPane input[type=\\\"datetime-local\\\"],\\n.contactPane input[type=\\\"datetime-local\\\"] {\\n min-height: var(--min-touch-target);\\n}\\n\\n.individualPane .hoverControl:has(> img:first-child):focus-visible,\\n.contactPane .hoverControl:has(> img:first-child):focus-visible,\\n.individualPane button:focus-visible,\\n.contactPane button:focus-visible,\\n.individualPane input:not([type=\\\"color\\\"]):focus-visible,\\n.contactPane input:not([type=\\\"color\\\"]):focus-visible,\\n.individualPane textarea:focus-visible,\\n.contactPane textarea:focus-visible,\\n.individualPane select:focus-visible,\\n.contactPane select:focus-visible {\\n outline: var(--focus-ring-width) solid var(--color-primary) !important;\\n outline-offset: 2px;\\n box-shadow: 0 0 0 1px var(--color-background);\\n}\\n\\n.individualPane input[type=\\\"url\\\"],\\n.contactPane input[type=\\\"url\\\"] {\\n width: 99%;\\n}\\n\\n.individualPane .formFieldValue,\\n.contactPane .formFieldValue {\\n min-width: 0;\\n margin-bottom: var(--spacing-sm);\\n}\\n\\n.individualPane .formFieldValue table,\\n.contactPane .formFieldValue table {\\n margin: 0 !important;\\n padding: 0 !important;\\n}\\n\\n.individualPane .formFieldValue td,\\n.contactPane .formFieldValue td {\\n padding: 0 !important;\\n vertical-align: middle;\\n}\\n\\n.individualPane .formFieldValue table[data-testid=\\\"autocomplete-table\\\"],\\n.contactPane .formFieldValue table[data-testid=\\\"autocomplete-table\\\"] {\\n height: 100%;\\n}\\n\\n.individualPane .formFieldValue input:not([type=\\\"color\\\"]),\\n.contactPane .formFieldValue input:not([type=\\\"color\\\"]),\\n.individualPane .formFieldValue textarea,\\n.contactPane .formFieldValue textarea {\\n width: 99% !important;\\n max-width: 99%;\\n}\\n\\n/* Email and phone value inputs: do not stretch full width */\\n.individualPane .formFieldName:has(a[href=\\\"http://www.w3.org/2006/vcard/ns#value\\\"]) + .formFieldValue input:not([type=\\\"color\\\"]),\\n.contactPane .formFieldName:has(a[href=\\\"http://www.w3.org/2006/vcard/ns#value\\\"]) + .formFieldValue input:not([type=\\\"color\\\"]) {\\n width: 98% !important;\\n max-width: 98%;\\n}\\n\\n.individualPane .formFieldValue select,\\n.contactPane .formFieldValue select {\\n width: 99%;\\n display: inline-block;\\n max-width: none !important;\\n}\\n\\n.individualPane select#formSelect,\\n.contactPane select#formSelect {\\n width: 99%;\\n max-width: 98%;\\n box-sizing: border-box;\\n margin-left: 0 !important;\\n margin-right: 0 !important;\\n}\\n\\n.individualPane span select,\\n.contactPane span select {\\n max-width: 96% !important;\\n box-sizing: border-box;\\n margin: 0 !important;\\n}\\n\\n.individualPane .formFieldValue span select,\\n.contactPane .formFieldValue span select {\\n margin-left: 0 !important;\\n margin-right: 0 !important;\\n}\\n\\n/* Remove border/padding from the first wrapper div (and its first child wrapper). */\\n.individualPane > div:first-of-type,\\n.contactPane > div:first-of-type,\\n.individualPane > div:first-of-type > div:first-of-type,\\n.contactPane > div:first-of-type > div:first-of-type {\\n border: none !important;\\n padding: 0 !important;\\n}\\n\\n/* In contactPane, remove border/padding from all direct child divs. */\\n.individualPane > div,\\n.contactPane > div {\\n border: none !important;\\n padding: 0 !important;\\n}\\n\\n/* Align schema.org, solid terms, FOAF, vCard, and org field labels with their input values. */\\n.individualPane :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue),\\n.contactPane :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue) {\\n display: flex;\\n align-items: baseline;\\n margin-bottom: var(--spacing-sm);\\n}\\n\\n/* for the Resume inside corporation choice */\\n/* Add space between classifierBox label and select box */\\n.individualPane .choiceBox .classifierBox-label,\\n.contactPane .choiceBox .classifierBox-label {\\n margin-right: 0;\\n padding-left: var(--spacing-xxs);\\n}\\n\\n.individualPane .choiceBox .choiceBox-selectBox select,\\n.contactPane .choiceBox .choiceBox-selectBox select {\\n margin-left: 2.1em !important;\\n}\\n\\n/* for the Resume orga details */\\n/* Add space between classifierBox label and select box */\\n.individualPane .classifierBox .classifierBox-label,\\n.contactPane .classifierBox .classifierBox-label {\\n margin-right: 0;\\n padding-left: var(--spacing-xxs);\\n width: 8em;\\n padding: var(--spacing-xxs);\\n vertical-align: middle;\\n}\\n\\n.individualPane .classifierBox .classifierBox-selectBox,\\n.contactPane .classifierBox .classifierBox-selectBox {\\n margin-left: 0 !important;\\n}\\n\\n.individualPane .classifierBox .classifierBox-selectBox select,\\n.contactPane .classifierBox .classifierBox-selectBox select {\\n margin-left: 0 !important;\\n}\\n\\n.individualPane .formFieldValue > span > select,\\n.contactPane .formFieldValue > span > select {\\n margin-left: 0 !important;\\n}\\n\\n.individualPane :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue) > .formFieldValue,\\n.contactPane :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue) > .formFieldValue {\\n margin-bottom: 0;\\n}\\n\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://schema.org/\\\"]),\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://schema.org/\\\"]),\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/ns/solid/terms#\\\"]),\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/ns/solid/terms#\\\"]),\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://xmlns.com/foaf/0.1/\\\"]),\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://xmlns.com/foaf/0.1/\\\"]),\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/2006/vcard/ns\\\"]),\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/2006/vcard/ns\\\"]),\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/ns/org#\\\"]),\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/ns/org#\\\"]) {\\n display: inline-flex;\\n align-items: center;\\n vertical-align: middle;\\n}\\n\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://schema.org/\\\"]) + .formFieldValue,\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://schema.org/\\\"]) + .formFieldValue,\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/ns/solid/terms#\\\"]) + .formFieldValue,\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/ns/solid/terms#\\\"]) + .formFieldValue,\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://xmlns.com/foaf/0.1/\\\"]) + .formFieldValue,\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://xmlns.com/foaf/0.1/\\\"]) + .formFieldValue,\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/2006/vcard/ns\\\"]) + .formFieldValue,\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/2006/vcard/ns\\\"]) + .formFieldValue,\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/ns/org#\\\"]) + .formFieldValue,\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/ns/org#\\\"]) + .formFieldValue {\\n display: inline-flex;\\n align-items: center;\\n vertical-align: middle;\\n flex: 1;\\n min-width: 0;\\n}\\n\\n/* Center textarea label vertically in flex rows. */\\n.individualPane div[style*=\\\"display: flex\\\"][style*=\\\"flex-direction: row\\\"]:has(textarea),\\n.contactPane div[style*=\\\"display: flex\\\"][style*=\\\"flex-direction: row\\\"]:has(textarea) {\\n align-items: flex-start;\\n}\\n\\n.individualPane div[style*=\\\"display: flex\\\"][style*=\\\"flex-direction: row\\\"]:has(textarea) > div:has(> a),\\n.contactPane div[style*=\\\"display: flex\\\"][style*=\\\"flex-direction: row\\\"]:has(textarea) > div:has(> a) {\\n padding-left: var(--spacing-xs);\\n padding-top: var(--spacing-sm);\\n}\\n\\n/* Keep autocomplete/table-based fields (e.g. Occupation) aligned to label text baseline. */\\n.individualPane :not(.choiceBox):has(> .formFieldValue input[data-testid=\\\"autocomplete-input\\\"]),\\n.contactPane :not(.choiceBox):has(> .formFieldValue input[data-testid=\\\"autocomplete-input\\\"]) {\\n align-items: flex-start;\\n}\\n\\n.individualPane :not(.choiceBox):has(> .formFieldValue input[data-testid=\\\"autocomplete-input\\\"]) > .formFieldName,\\n.contactPane :not(.choiceBox):has(> .formFieldValue input[data-testid=\\\"autocomplete-input\\\"]) > .formFieldName {\\n padding-top: var(--spacing-xs) !important;\\n}\\n\\n.individualPane .formFieldValue:has(input[data-testid=\\\"autocomplete-input\\\"]),\\n.contactPane .formFieldValue:has(input[data-testid=\\\"autocomplete-input\\\"]) {\\n align-self: flex-start;\\n}\\n\\n.individualPane .formFieldValue table[data-testid=\\\"autocomplete-table\\\"],\\n.contactPane .formFieldValue table[data-testid=\\\"autocomplete-table\\\"],\\n.individualPane .formFieldValue input[data-testid=\\\"autocomplete-input\\\"],\\n.contactPane .formFieldValue input[data-testid=\\\"autocomplete-input\\\"] {\\n margin: 0 !important;\\n}\\n\\n.individualPane .formFieldValue table[data-testid=\\\"autocomplete-table\\\"],\\n.contactPane .formFieldValue table[data-testid=\\\"autocomplete-table\\\"] {\\n vertical-align: baseline;\\n}\\n\\n.individualPane input:disabled,\\n.contactPane input:disabled,\\n.individualPane textarea:disabled,\\n.contactPane textarea:disabled,\\n.individualPane select:disabled,\\n.contactPane select:disabled,\\n.individualPane input[readonly],\\n.contactPane input[readonly],\\n.individualPane textarea[readonly],\\n.contactPane textarea[readonly],\\n.individualPane input:read-only,\\n.contactPane input:read-only,\\n.individualPane textarea:read-only,\\n.contactPane textarea:read-only {\\n background-color: var(--color-background) !important;\\n cursor: not-allowed;\\n opacity: var(--opacity-input-disabled);\\n border: var(--border-width-xthin) solid var(--color-background) !important;\\n}\\n\\n.contactPane .webidControl table td div.contactPane.namedPane {\\n border: none !important;\\n}\\n\\n/* ------------------------------------------------------------------ */\\n/* inline popup used for small confirmation flows (like the new confirmDialog) */\\n/* apply the class `rdf-inline-modal` on the outer wrapper and give the\\n inner box the class `popup` instead of using the old inline styles. */\\n\\n/* selectors that match the old inline-styled markup when no classes can be added */\\n\\n/* Delete pop up */\\n/* Remove the intermediate positioned ancestor so the popup anchors to .hoverControl instead */\\n.individualPane div[style*=\\\"position: relative\\\"]:has(> div[style*=\\\"display: grid\\\"]) {\\n position: static !important;\\n}\\n\\n.individualPane div[style*=\\\"position: relative\\\"] > div[style*=\\\"display: grid\\\"] {\\n /* override inline values with theme variables */\\n position: absolute !important;\\n top: 0 !important;\\n right: 0 !important;\\n left: auto !important;\\n z-index: 9999 !important;\\n display: grid !important;\\n pointer-events: auto !important;\\n opacity: 1 !important;\\n visibility: visible !important;\\n padding: var(--spacing-btn) !important;\\n background: var(--color-background) !important;\\n border: var(--border-width-sm) solid var(--color-primary) !important;\\n border-radius: var(--border-radius-base) !important;\\n box-shadow: var(--box-shadow-popup) !important;\\n grid-template-columns: auto auto !important;\\n gap: var(--spacing-xxs) !important;\\n}\\n\\n.individualPane .hoverControl img.hoverControlHide,\\n.individualPane .hoverControl [data-testid=\\\"deleteButtonWithCheck\\\"] {\\n position: absolute !important;\\n right: var(--spacing-xxxs) !important;\\n width: 1.5em !important;\\n height: 1.5em !important;\\n display: none !important;\\n align-items: center;\\n justify-content: center;\\n margin: 0 !important;\\n float: none !important;\\n z-index: 2 !important;\\n}\\n\\n/* Show delete icon only on hover */\\n.individualPane .hoverControl:hover img.hoverControlHide,\\n.individualPane .hoverControl:hover [data-testid=\\\"deleteButtonWithCheck\\\"] {\\n display: inline-flex !important;\\n}\\n\\n/* If the hoverControl has exactly one div + the delete icon, keep the icon vertically centered but right-aligned */\\n.individualPane .hoverControl:has(> div:nth-child(1):nth-last-child(2)):hover > img.hoverControlHide,\\n.individualPane .hoverControl:has(> div:nth-child(1):nth-last-child(2)):hover > [data-testid=\\\"deleteButtonWithCheck\\\"] {\\n top: 50% !important;\\n right: var(--spacing-xxxs) !important;\\n left: auto !important;\\n transform: translateY(-50%) !important;\\n}\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* ── Group Membership Section ──────────────────────────────── */\n\n.contactPane .group-membership-container {\n padding: var(--spacing-sm) 0;\n}\n\n/* Grid wrapper — matches detailsSectionContent groupButtonsList */\n.contactPane .group-pills-wrapper {\n display: grid !important;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)) !important;\n gap: var(--spacing-sm) !important;\n list-style: none;\n padding: 0;\n margin: 0;\n width: 100% !important;\n}\n\n.contactPane .group-pills-wrapper span {\n width: max-content !important;\n}\n\n/* Each group item: button on top, toolbar below */\n.contactPane .group-membership-item {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n max-width: 256px;\n}\n\n.contactPane .group-membership-item > button {\n width: 100%;\n text-align: center;\n border-radius: var(--border-radius-base);\n word-wrap: break-word;\n overflow-wrap: break-word;\n min-height: var(--min-touch-target);\n}\n\n/* Toolbar with link icon and delete button below each group button */\n.contactPane .group-membership-item .group-membership-toolbar {\n display: flex;\n align-items: center;\n gap: var(--spacing-xs);\n padding: var(--spacing-xs) 0 0 0;\n}\n\n.contactPane .group-membership-item .group-membership-toolbar a {\n margin: 0.3em;\n margin-left: 1em;\n}\n\n.contactPane .group-membership-item .group-membership-toolbar a img {\n width: 1.3em;\n height: 1em;\n margin: 0;\n}\n\n/* Cancel float:right and any absolute positioning injected by solid-ui */\n.contactPane .group-membership-item .group-membership-toolbar > img.hoverControlHide,\n.contactPane .group-membership-item .group-membership-toolbar > [data-testid=\"deleteButtonWithCheck\"] {\n float: none !important;\n display: inline-flex !important;\n visibility: hidden !important;\n margin: 0 !important;\n}\n\n.contactPane .group-membership-item .group-membership-toolbar:hover > img.hoverControlHide,\n.contactPane .group-membership-item .group-membership-toolbar:hover > [data-testid=\"deleteButtonWithCheck\"] {\n visibility: visible !important;\n}\n\n.contactPane .detailsSectionContent .group-membership-item .group-membership-toolbar > div[style*=\"position: relative\"] {\n position: absolute !important;\n top: 0 !important;\n left: 50% !important;\n transform: translateX(-50%) !important;\n width: min(90vw, 440px) !important;\n min-width: 280px !important;\n max-width: 90vw !important;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n}\n\n.contactPane .detailsSectionContent .group-membership-item .group-membership-toolbar > div[style*=\"position: relative\"] > div {\n position: relative !important;\n top: auto !important;\n min-width: 280px !important;\n background: var(--color-background);\n border-radius: var(--border-radius-full);\n padding: var(--spacing-lg);\n box-shadow: var(--box-shadow-overlay);\n z-index: 1001;\n}\n\n@media (max-width: 599px) {\n .contactPane .group-membership-item .group-pills-wrapper {\n grid-template-columns: repeat(2, 1fr) !important;\n gap: var(--spacing-xs) !important;\n max-width: 100% !important;\n }\n\n .contactPane .group-membership-item .group-membership-item > button {\n font-size: var(--font-size-sm) !important;\n border-radius: var(--border-radius-base) !important;\n }\n}\n\n@media (min-width: 900px) {\n .contactPane .group-membership-item .group-pills-wrapper {\n grid-template-columns: repeat(3, 1fr) !important;\n gap: var(--spacing-sm) !important;\n }\n}\n`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/groupMembership.css\"],\"names\":[],\"mappings\":\"AAAA,iEAAiE;;AAEjE;EACE,4BAA4B;AAC9B;;AAEA,kEAAkE;AAClE;EACE,wBAAwB;EACxB,sEAAsE;EACtE,iCAAiC;EACjC,gBAAgB;EAChB,UAAU;EACV,SAAS;EACT,sBAAsB;AACxB;;AAEA;EACE,6BAA6B;AAC/B;;AAEA,kDAAkD;AAClD;EACE,aAAa;EACb,sBAAsB;EACtB,oBAAoB;EACpB,gBAAgB;AAClB;;AAEA;EACE,WAAW;EACX,kBAAkB;EAClB,wCAAwC;EACxC,qBAAqB;EACrB,yBAAyB;EACzB,mCAAmC;AACrC;;AAEA,qEAAqE;AACrE;EACE,aAAa;EACb,mBAAmB;EACnB,sBAAsB;EACtB,gCAAgC;AAClC;;AAEA;EACE,aAAa;EACb,gBAAgB;AAClB;;AAEA;EACE,YAAY;EACZ,WAAW;EACX,SAAS;AACX;;AAEA,yEAAyE;AACzE;;EAEE,sBAAsB;EACtB,+BAA+B;EAC/B,6BAA6B;EAC7B,oBAAoB;AACtB;;AAEA;;EAEE,8BAA8B;AAChC;;AAEA;EACE,6BAA6B;EAC7B,iBAAiB;EACjB,oBAAoB;EACpB,sCAAsC;EACtC,kCAAkC;EAClC,2BAA2B;EAC3B,0BAA0B;EAC1B,aAAa;EACb,mBAAmB;EACnB,uBAAuB;EACvB,aAAa;AACf;;AAEA;EACE,6BAA6B;EAC7B,oBAAoB;EACpB,2BAA2B;EAC3B,mCAAmC;EACnC,wCAAwC;EACxC,0BAA0B;EAC1B,qCAAqC;EACrC,aAAa;AACf;;AAEA;EACE;IACE,gDAAgD;IAChD,iCAAiC;IACjC,0BAA0B;EAC5B;;EAEA;IACE,yCAAyC;IACzC,mDAAmD;EACrD;AACF;;AAEA;EACE;IACE,gDAAgD;IAChD,iCAAiC;EACnC;AACF\",\"sourcesContent\":[\"/* ── Group Membership Section ──────────────────────────────── */\\n\\n.contactPane .group-membership-container {\\n padding: var(--spacing-sm) 0;\\n}\\n\\n/* Grid wrapper — matches detailsSectionContent groupButtonsList */\\n.contactPane .group-pills-wrapper {\\n display: grid !important;\\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)) !important;\\n gap: var(--spacing-sm) !important;\\n list-style: none;\\n padding: 0;\\n margin: 0;\\n width: 100% !important;\\n}\\n\\n.contactPane .group-pills-wrapper span {\\n width: max-content !important;\\n}\\n\\n/* Each group item: button on top, toolbar below */\\n.contactPane .group-membership-item {\\n display: flex;\\n flex-direction: column;\\n align-items: stretch;\\n max-width: 256px;\\n}\\n\\n.contactPane .group-membership-item > button {\\n width: 100%;\\n text-align: center;\\n border-radius: var(--border-radius-base);\\n word-wrap: break-word;\\n overflow-wrap: break-word;\\n min-height: var(--min-touch-target);\\n}\\n\\n/* Toolbar with link icon and delete button below each group button */\\n.contactPane .group-membership-item .group-membership-toolbar {\\n display: flex;\\n align-items: center;\\n gap: var(--spacing-xs);\\n padding: var(--spacing-xs) 0 0 0;\\n}\\n\\n.contactPane .group-membership-item .group-membership-toolbar a {\\n margin: 0.3em;\\n margin-left: 1em;\\n}\\n\\n.contactPane .group-membership-item .group-membership-toolbar a img {\\n width: 1.3em;\\n height: 1em;\\n margin: 0;\\n}\\n\\n/* Cancel float:right and any absolute positioning injected by solid-ui */\\n.contactPane .group-membership-item .group-membership-toolbar > img.hoverControlHide,\\n.contactPane .group-membership-item .group-membership-toolbar > [data-testid=\\\"deleteButtonWithCheck\\\"] {\\n float: none !important;\\n display: inline-flex !important;\\n visibility: hidden !important;\\n margin: 0 !important;\\n}\\n\\n.contactPane .group-membership-item .group-membership-toolbar:hover > img.hoverControlHide,\\n.contactPane .group-membership-item .group-membership-toolbar:hover > [data-testid=\\\"deleteButtonWithCheck\\\"] {\\n visibility: visible !important;\\n}\\n\\n.contactPane .detailsSectionContent .group-membership-item .group-membership-toolbar > div[style*=\\\"position: relative\\\"] {\\n position: absolute !important;\\n top: 0 !important;\\n left: 50% !important;\\n transform: translateX(-50%) !important;\\n width: min(90vw, 440px) !important;\\n min-width: 280px !important;\\n max-width: 90vw !important;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n z-index: 1000;\\n}\\n\\n.contactPane .detailsSectionContent .group-membership-item .group-membership-toolbar > div[style*=\\\"position: relative\\\"] > div {\\n position: relative !important;\\n top: auto !important;\\n min-width: 280px !important;\\n background: var(--color-background);\\n border-radius: var(--border-radius-full);\\n padding: var(--spacing-lg);\\n box-shadow: var(--box-shadow-overlay);\\n z-index: 1001;\\n}\\n\\n@media (max-width: 599px) {\\n .contactPane .group-membership-item .group-pills-wrapper {\\n grid-template-columns: repeat(2, 1fr) !important;\\n gap: var(--spacing-xs) !important;\\n max-width: 100% !important;\\n }\\n\\n .contactPane .group-membership-item .group-membership-item > button {\\n font-size: var(--font-size-sm) !important;\\n border-radius: var(--border-radius-base) !important;\\n }\\n}\\n\\n@media (min-width: 900px) {\\n .contactPane .group-membership-item .group-pills-wrapper {\\n grid-template-columns: repeat(3, 1fr) !important;\\n gap: var(--spacing-sm) !important;\\n }\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* individual.js styles — extracted from inline styles */\n\n/* ── Individual pane container ───────────────────────────────── */\n\n.individualPane {\n padding: var(--spacing-xs) var(--spacing-lg) var(--spacing-md) var(--spacing-lg);\n background: var(--color-section-bg);\n border-radius: var(--border-radius-full);\n box-shadow: var(--box-shadow);\n box-sizing: border-box;\n max-width: 100%;\n}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/individual.css\"],\"names\":[],\"mappings\":\"AAAA,wDAAwD;;AAExD,mEAAmE;;AAEnE;EACE,gFAAgF;EAChF,mCAAmC;EACnC,wCAAwC;EACxC,6BAA6B;EAC7B,sBAAsB;EACtB,eAAe;AACjB\",\"sourcesContent\":[\"/* individual.js styles — extracted from inline styles */\\n\\n/* ── Individual pane container ───────────────────────────────── */\\n\\n.individualPane {\\n padding: var(--spacing-xs) var(--spacing-lg) var(--spacing-md) var(--spacing-lg);\\n background: var(--color-section-bg);\\n border-radius: var(--border-radius-full);\\n box-shadow: var(--box-shadow);\\n box-sizing: border-box;\\n max-width: 100%;\\n}\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* CSS for the accessible modal dialogs created by localUtils.js */\n\n/* backdrop / focus trap container */\n.focus-trap {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 9999;\n background: var(--overlay-bg);\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n/* inner dialog box */\n.focus-trap .modal {\n background: var(--color-background);\n padding: var(--spacing-lg);\n border-radius: var(--border-radius-base);\n max-width: 90%;\n box-shadow: var(--box-shadow-modal);\n}\n\n/* button container: center buttons horizontally (uses id in markup) */\n#contacts-modal #modal-buttons {\n margin-top: var(--spacing-md);\n display: flex;\n justify-content: center;\n gap: var(--spacing-sm);\n}\n\n/* buttons themselves use the shared btn-primary rules */\n#contacts-modal .modal button {\n min-height: var(--min-touch-target);\n padding: var(--spacing-sm) var(--spacing-md);\n border: 1px solid var(--color-primary);\n border-radius: var(--border-radius-base);\n font-weight: 600;\n cursor: pointer;\n transition: all var(--animation-duration) ease;\n}\n\n#contacts-modal .modal button:disabled {\n opacity: var(--opacity-disabled);\n cursor: not-allowed;\n transform: none;\n}\n`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/localUtils.css\"],\"names\":[],\"mappings\":\"AAAA,kEAAkE;;AAElE,oCAAoC;AACpC;EACE,eAAe;EACf,MAAM;EACN,OAAO;EACP,WAAW;EACX,YAAY;EACZ,aAAa;EACb,6BAA6B;EAC7B,aAAa;EACb,uBAAuB;EACvB,mBAAmB;AACrB;;AAEA,qBAAqB;AACrB;EACE,mCAAmC;EACnC,0BAA0B;EAC1B,wCAAwC;EACxC,cAAc;EACd,mCAAmC;AACrC;;AAEA,sEAAsE;AACtE;EACE,6BAA6B;EAC7B,aAAa;EACb,uBAAuB;EACvB,sBAAsB;AACxB;;AAEA,wDAAwD;AACxD;EACE,mCAAmC;EACnC,4CAA4C;EAC5C,sCAAsC;EACtC,wCAAwC;EACxC,gBAAgB;EAChB,eAAe;EACf,8CAA8C;AAChD;;AAEA;EACE,gCAAgC;EAChC,mBAAmB;EACnB,eAAe;AACjB\",\"sourcesContent\":[\"/* CSS for the accessible modal dialogs created by localUtils.js */\\n\\n/* backdrop / focus trap container */\\n.focus-trap {\\n position: fixed;\\n top: 0;\\n left: 0;\\n width: 100%;\\n height: 100%;\\n z-index: 9999;\\n background: var(--overlay-bg);\\n display: flex;\\n justify-content: center;\\n align-items: center;\\n}\\n\\n/* inner dialog box */\\n.focus-trap .modal {\\n background: var(--color-background);\\n padding: var(--spacing-lg);\\n border-radius: var(--border-radius-base);\\n max-width: 90%;\\n box-shadow: var(--box-shadow-modal);\\n}\\n\\n/* button container: center buttons horizontally (uses id in markup) */\\n#contacts-modal #modal-buttons {\\n margin-top: var(--spacing-md);\\n display: flex;\\n justify-content: center;\\n gap: var(--spacing-sm);\\n}\\n\\n/* buttons themselves use the shared btn-primary rules */\\n#contacts-modal .modal button {\\n min-height: var(--min-touch-target);\\n padding: var(--spacing-sm) var(--spacing-md);\\n border: 1px solid var(--color-primary);\\n border-radius: var(--border-radius-base);\\n font-weight: 600;\\n cursor: pointer;\\n transition: all var(--animation-duration) ease;\\n}\\n\\n#contacts-modal .modal button:disabled {\\n opacity: var(--opacity-disabled);\\n cursor: not-allowed;\\n transform: none;\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* mugshotGallery.js styles — extracted from inline styles */\n/* Uses CSS custom properties from the global stylesheet (dev-global.css / mashlib) */\n\n/* ── Mugshot image ───────────────────────────────────────────── */\n\n.contactPane .mugshotImage {\n max-height: 10em;\n border-radius: var(--border-radius-full);\n margin: var(--spacing-sm);\n}\n\n.contactPane button:has(> img[src\\$=\".svg\"]) {\n background-color: var(--color-section-bg) !important;\n border: none !important;\n margin: 0 !important;\n border-radius: 0 !important;\n}\n`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/mugshotGallery.css\"],\"names\":[],\"mappings\":\"AAAA,4DAA4D;AAC5D,qFAAqF;;AAErF,mEAAmE;;AAEnE;EACE,gBAAgB;EAChB,wCAAwC;EACxC,yBAAyB;AAC3B;;AAEA;EACE,oDAAoD;EACpD,uBAAuB;EACvB,oBAAoB;EACpB,2BAA2B;AAC7B\",\"sourcesContent\":[\"/* mugshotGallery.js styles — extracted from inline styles */\\n/* Uses CSS custom properties from the global stylesheet (dev-global.css / mashlib) */\\n\\n/* ── Mugshot image ───────────────────────────────────────────── */\\n\\n.contactPane .mugshotImage {\\n max-height: 10em;\\n border-radius: var(--border-radius-full);\\n margin: var(--spacing-sm);\\n}\\n\\n.contactPane button:has(> img[src$=\\\".svg\\\"]) {\\n background-color: var(--color-section-bg) !important;\\n border: none !important;\\n margin: 0 !important;\\n border-radius: 0 !important;\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* toolsPane.js styles — extracted from inline styles */\n/* Uses CSS custom properties from the global stylesheet (dev-global.css / mashlib) */\n\n/* ── Tools pane table ────────────────────────────────────────── */\n\n.contactPane .statsLog {\n font-size: var(--font-size-lg);\n margin: var(--spacing-md);\n background-color: var(--color-background);\n}\n\n.contactPane .statsLog pre {\n padding: var(--spacing-md);\n white-space: pre-wrap;\n word-wrap: break-word;\n overflow-wrap: break-word;\n overflow: hidden;\n max-width: 100%;\n}\n\n/* ── Tools pane layout ────────────────────────────────────────── */\n\n.contactPane .toolsPane {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-xs);\n}\n\n.contactPane .toolsButtonsContainer {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-xs);\n}\n\n/* ── Load index button states ──────────────────────────────── */\n\n.contactPane .toolsButton--error {\n background-color: var(--color-error);\n}\n\n.contactPane .toolsButton--success {\n background-color: var(--color-primary);\n}\n`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/toolsPane.css\"],\"names\":[],\"mappings\":\"AAAA,uDAAuD;AACvD,qFAAqF;;AAErF,mEAAmE;;AAEnE;EACE,8BAA8B;EAC9B,yBAAyB;EACzB,yCAAyC;AAC3C;;AAEA;EACE,0BAA0B;EAC1B,qBAAqB;EACrB,qBAAqB;EACrB,yBAAyB;EACzB,gBAAgB;EAChB,eAAe;AACjB;;AAEA,oEAAoE;;AAEpE;EACE,aAAa;EACb,sBAAsB;EACtB,sBAAsB;AACxB;;AAEA;EACE,aAAa;EACb,eAAe;EACf,sBAAsB;AACxB;;AAEA,iEAAiE;;AAEjE;EACE,oCAAoC;AACtC;;AAEA;EACE,sCAAsC;AACxC\",\"sourcesContent\":[\"/* toolsPane.js styles — extracted from inline styles */\\n/* Uses CSS custom properties from the global stylesheet (dev-global.css / mashlib) */\\n\\n/* ── Tools pane table ────────────────────────────────────────── */\\n\\n.contactPane .statsLog {\\n font-size: var(--font-size-lg);\\n margin: var(--spacing-md);\\n background-color: var(--color-background);\\n}\\n\\n.contactPane .statsLog pre {\\n padding: var(--spacing-md);\\n white-space: pre-wrap;\\n word-wrap: break-word;\\n overflow-wrap: break-word;\\n overflow: hidden;\\n max-width: 100%;\\n}\\n\\n/* ── Tools pane layout ────────────────────────────────────────── */\\n\\n.contactPane .toolsPane {\\n display: flex;\\n flex-direction: column;\\n gap: var(--spacing-xs);\\n}\\n\\n.contactPane .toolsButtonsContainer {\\n display: flex;\\n flex-wrap: wrap;\\n gap: var(--spacing-xs);\\n}\\n\\n/* ── Load index button states ──────────────────────────────── */\\n\\n.contactPane .toolsButton--error {\\n background-color: var(--color-error);\\n}\\n\\n.contactPane .toolsButton--success {\\n background-color: var(--color-primary);\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* Shared utility variables for component styles.\n These are kept here (instead of in dev-global.css) so they can be\n bundled with component styles and reused consistently across the app.\n*/\n\n/* Utility helper classes */\n.hidden {\n display: none !important;\n}\n\n.btn-primary {\n min-height: var(--min-touch-target);\n padding: var(--spacing-sm) var(--spacing-md);\n border: 1px solid var(--color-primary);\n border-radius: var(--border-radius-base);\n background: var(--color-primary);\n color: var(--color-background);\n font-weight: 600;\n cursor: pointer;\n transition: all var(--animation-duration) ease;\n}\n\n.btn-primary:hover {\n background: color-mix(in srgb, var(--color-primary) 90%, black);\n box-shadow: var(--box-shadow-hover);\n}\n\n.btn-primary:active {\n box-shadow: var(--box-shadow-active);\n}\n\n.btn-primary:disabled {\n opacity: var(--opacity-disabled);\n cursor: not-allowed;\n transform: none;\n}\n\n.btn-secondary {\n min-height: var(--min-touch-target);\n padding: var(--spacing-sm) var(--spacing-md);\n border: var(--border-width-thin) solid var(--color-secondary);\n border-radius: var(--border-radius-base);\n background: var(--color-secondary);\n color: var(--color-background);\n font-weight: var(--font-weight-bold);\n cursor: pointer;\n transition: all var(--animation-duration) ease;\n text-decoration: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.btn-secondary:hover {\n background: color-mix(in srgb, var(--color-secondary) 85%, black);\n}\n\n.btn-secondary:disabled {\n opacity: var(--opacity-disabled);\n cursor: not-allowed;\n}\n\n.action-button-focus:focus,\n.action-button-focus:focus-visible {\n outline: 3px solid var(--color-primary) !important;\n outline-offset: 2px !important;\n box-shadow: 0 0 0 2px var(--color-background), var(--box-shadow-focus) !important;\n z-index: 1;\n}\n`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/utilities.css\"],\"names\":[],\"mappings\":\"AAAA;;;CAGC;;AAED,2BAA2B;AAC3B;EACE,wBAAwB;AAC1B;;AAEA;EACE,mCAAmC;EACnC,4CAA4C;EAC5C,sCAAsC;EACtC,wCAAwC;EACxC,gCAAgC;EAChC,8BAA8B;EAC9B,gBAAgB;EAChB,eAAe;EACf,8CAA8C;AAChD;;AAEA;EACE,+DAA+D;EAC/D,mCAAmC;AACrC;;AAEA;EACE,oCAAoC;AACtC;;AAEA;EACE,gCAAgC;EAChC,mBAAmB;EACnB,eAAe;AACjB;;AAEA;EACE,mCAAmC;EACnC,4CAA4C;EAC5C,6DAA6D;EAC7D,wCAAwC;EACxC,kCAAkC;EAClC,8BAA8B;EAC9B,oCAAoC;EACpC,eAAe;EACf,8CAA8C;EAC9C,qBAAqB;EACrB,oBAAoB;EACpB,mBAAmB;EACnB,uBAAuB;AACzB;;AAEA;EACE,iEAAiE;AACnE;;AAEA;EACE,gCAAgC;EAChC,mBAAmB;AACrB;;AAEA;;EAEE,kDAAkD;EAClD,8BAA8B;EAC9B,iFAAiF;EACjF,UAAU;AACZ\",\"sourcesContent\":[\"/* Shared utility variables for component styles.\\n These are kept here (instead of in dev-global.css) so they can be\\n bundled with component styles and reused consistently across the app.\\n*/\\n\\n/* Utility helper classes */\\n.hidden {\\n display: none !important;\\n}\\n\\n.btn-primary {\\n min-height: var(--min-touch-target);\\n padding: var(--spacing-sm) var(--spacing-md);\\n border: 1px solid var(--color-primary);\\n border-radius: var(--border-radius-base);\\n background: var(--color-primary);\\n color: var(--color-background);\\n font-weight: 600;\\n cursor: pointer;\\n transition: all var(--animation-duration) ease;\\n}\\n\\n.btn-primary:hover {\\n background: color-mix(in srgb, var(--color-primary) 90%, black);\\n box-shadow: var(--box-shadow-hover);\\n}\\n\\n.btn-primary:active {\\n box-shadow: var(--box-shadow-active);\\n}\\n\\n.btn-primary:disabled {\\n opacity: var(--opacity-disabled);\\n cursor: not-allowed;\\n transform: none;\\n}\\n\\n.btn-secondary {\\n min-height: var(--min-touch-target);\\n padding: var(--spacing-sm) var(--spacing-md);\\n border: var(--border-width-thin) solid var(--color-secondary);\\n border-radius: var(--border-radius-base);\\n background: var(--color-secondary);\\n color: var(--color-background);\\n font-weight: var(--font-weight-bold);\\n cursor: pointer;\\n transition: all var(--animation-duration) ease;\\n text-decoration: none;\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n}\\n\\n.btn-secondary:hover {\\n background: color-mix(in srgb, var(--color-secondary) 85%, black);\\n}\\n\\n.btn-secondary:disabled {\\n opacity: var(--opacity-disabled);\\n cursor: not-allowed;\\n}\\n\\n.action-button-focus:focus,\\n.action-button-focus:focus-visible {\\n outline: 3px solid var(--color-primary) !important;\\n outline-offset: 2px !important;\\n box-shadow: 0 0 0 2px var(--color-background), var(--box-shadow-focus) !important;\\n z-index: 1;\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* ── Named pane (rendered sub-pane) ──────────────────────────── */\n.contactPane .namedPane {\n border: var(--border-width-sm) solid var(--color-text-muted);\n border-radius: var(--border-radius-base);\n}\n\n/* ── Persona row ─────────────────────────────────────────────── */\n\n.contactPane .personaRow {\n padding: var(--spacing-xs);\n}\n\n.contactPane .personaRow--webid,\n.contactPane .personaRow--webid td,\n.contactPane .personaRow--webid button,\n.contactPane .personaRow--webid button:hover,\n.contactPane .personaRow--webid .hoverControl:has(> img:first-child),\n.contactPane .personaRow--webid .hoverControl:has(> img:first-child):hover,\n.contactPane .personaRow--webid .personaOpenButton:has(> img:first-child),\n.contactPane .personaRow--webid .personaOpenButton:has(> img:first-child):hover {\n background-color: var(--color-info-bg) !important;\n}\n\n/* ── Full-width elements ─────────────────────────────────────── */\n\n.contactPane .fullWidth {\n width: 100%;\n}\n\n/* ── Open/close profile button ───────────────────────────────── */\n\n.contactPane .personaOpenButton {\n float: right;\n background-color: transparent;\n border: none;\n}\n\n/* hoverControl layout overrides are now enforced in contactsRDFFormsEnforced.css */\n\n/* ── Delete confirmation popup in webidControl ───────────────── */\n\n/* Remove intermediate positioned ancestor so popup anchors to .hoverControl */\n.contactPane .webidControl div[style*=\"position: relative\"]:has(> div[style*=\"display: grid\"]) {\n position: static !important;\n}\n\n/* Position the popup absolutely so it never participates in the flex row */\n.contactPane .webidControl div[style*=\"position: relative\"] > div[style*=\"display: grid\"] {\n position: absolute !important;\n top: 0 !important;\n right: 0 !important;\n left: auto !important;\n z-index: 9999 !important;\n display: grid !important;\n pointer-events: auto !important;\n opacity: 1 !important;\n visibility: visible !important;\n padding: var(--spacing-btn) !important;\n min-width: 12em !important;\n background: var(--color-background) !important;\n border: var(--border-width-sm) solid var(--color-primary) !important;\n border-radius: var(--border-radius-base) !important;\n box-shadow: var(--box-shadow-popup) !important;\n grid-template-columns: auto auto !important;\n gap: var(--spacing-xxs) !important;\n}\n\n/* ── Section heading ─────────────────────────────────────────── */\n\n.contactPane .contactPanedHeading {\n font-size: var(--font-size-lg);\n font-weight: bold;\n color: var(--color-primary);\n margin: var(--spacing-sm) 0;\n}\n\n/* ── Prompt text ─────────────────────────────────────────────── */\n\n.contactPane .webidPrompt {\n padding: var(--spacing-sm);\n border: none;\n font-size: var(--font-size-base);\n white-space: pre-wrap;\n}\n\n/* ── Visibility / display helpers ────────────────────────────── */\n\n.contactPane .collapsed {\n visibility: collapse;\n}\n`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/webidControl.css\"],\"names\":[],\"mappings\":\"AAAA,mEAAmE;AACnE;EACE,4DAA4D;EAC5D,wCAAwC;AAC1C;;AAEA,mEAAmE;;AAEnE;EACE,0BAA0B;AAC5B;;AAEA;;;;;;;;EAQE,iDAAiD;AACnD;;AAEA,mEAAmE;;AAEnE;EACE,WAAW;AACb;;AAEA,mEAAmE;;AAEnE;EACE,YAAY;EACZ,6BAA6B;EAC7B,YAAY;AACd;;AAEA,mFAAmF;;AAEnF,mEAAmE;;AAEnE,8EAA8E;AAC9E;EACE,2BAA2B;AAC7B;;AAEA,2EAA2E;AAC3E;EACE,6BAA6B;EAC7B,iBAAiB;EACjB,mBAAmB;EACnB,qBAAqB;EACrB,wBAAwB;EACxB,wBAAwB;EACxB,+BAA+B;EAC/B,qBAAqB;EACrB,8BAA8B;EAC9B,sCAAsC;EACtC,0BAA0B;EAC1B,8CAA8C;EAC9C,oEAAoE;EACpE,mDAAmD;EACnD,8CAA8C;EAC9C,2CAA2C;EAC3C,kCAAkC;AACpC;;AAEA,mEAAmE;;AAEnE;EACE,8BAA8B;EAC9B,iBAAiB;EACjB,2BAA2B;EAC3B,2BAA2B;AAC7B;;AAEA,mEAAmE;;AAEnE;EACE,0BAA0B;EAC1B,YAAY;EACZ,gCAAgC;EAChC,qBAAqB;AACvB;;AAEA,mEAAmE;;AAEnE;EACE,oBAAoB;AACtB\",\"sourcesContent\":[\"/* ── Named pane (rendered sub-pane) ──────────────────────────── */\\n.contactPane .namedPane {\\n border: var(--border-width-sm) solid var(--color-text-muted);\\n border-radius: var(--border-radius-base);\\n}\\n\\n/* ── Persona row ─────────────────────────────────────────────── */\\n\\n.contactPane .personaRow {\\n padding: var(--spacing-xs);\\n}\\n\\n.contactPane .personaRow--webid,\\n.contactPane .personaRow--webid td,\\n.contactPane .personaRow--webid button,\\n.contactPane .personaRow--webid button:hover,\\n.contactPane .personaRow--webid .hoverControl:has(> img:first-child),\\n.contactPane .personaRow--webid .hoverControl:has(> img:first-child):hover,\\n.contactPane .personaRow--webid .personaOpenButton:has(> img:first-child),\\n.contactPane .personaRow--webid .personaOpenButton:has(> img:first-child):hover {\\n background-color: var(--color-info-bg) !important;\\n}\\n\\n/* ── Full-width elements ─────────────────────────────────────── */\\n\\n.contactPane .fullWidth {\\n width: 100%;\\n}\\n\\n/* ── Open/close profile button ───────────────────────────────── */\\n\\n.contactPane .personaOpenButton {\\n float: right;\\n background-color: transparent;\\n border: none;\\n}\\n\\n/* hoverControl layout overrides are now enforced in contactsRDFFormsEnforced.css */\\n\\n/* ── Delete confirmation popup in webidControl ───────────────── */\\n\\n/* Remove intermediate positioned ancestor so popup anchors to .hoverControl */\\n.contactPane .webidControl div[style*=\\\"position: relative\\\"]:has(> div[style*=\\\"display: grid\\\"]) {\\n position: static !important;\\n}\\n\\n/* Position the popup absolutely so it never participates in the flex row */\\n.contactPane .webidControl div[style*=\\\"position: relative\\\"] > div[style*=\\\"display: grid\\\"] {\\n position: absolute !important;\\n top: 0 !important;\\n right: 0 !important;\\n left: auto !important;\\n z-index: 9999 !important;\\n display: grid !important;\\n pointer-events: auto !important;\\n opacity: 1 !important;\\n visibility: visible !important;\\n padding: var(--spacing-btn) !important;\\n min-width: 12em !important;\\n background: var(--color-background) !important;\\n border: var(--border-width-sm) solid var(--color-primary) !important;\\n border-radius: var(--border-radius-base) !important;\\n box-shadow: var(--box-shadow-popup) !important;\\n grid-template-columns: auto auto !important;\\n gap: var(--spacing-xxs) !important;\\n}\\n\\n/* ── Section heading ─────────────────────────────────────────── */\\n\\n.contactPane .contactPanedHeading {\\n font-size: var(--font-size-lg);\\n font-weight: bold;\\n color: var(--color-primary);\\n margin: var(--spacing-sm) 0;\\n}\\n\\n/* ── Prompt text ─────────────────────────────────────────────── */\\n\\n.contactPane .webidPrompt {\\n padding: var(--spacing-sm);\\n border: none;\\n font-size: var(--font-size-base);\\n white-space: pre-wrap;\\n}\\n\\n/* ── Visibility / display helpers ────────────────────────────── */\\n\\n.contactPane .collapsed {\\n visibility: collapse;\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","\"use strict\";\n\n/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n*/\nmodule.exports = function (cssWithMappingToString) {\n var list = [];\n\n // return the list of modules as css string\n list.toString = function toString() {\n return this.map(function (item) {\n var content = \"\";\n var needLayer = typeof item[5] !== \"undefined\";\n if (item[4]) {\n content += \"@supports (\".concat(item[4], \") {\");\n }\n if (item[2]) {\n content += \"@media \".concat(item[2], \" {\");\n }\n if (needLayer) {\n content += \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\");\n }\n content += cssWithMappingToString(item);\n if (needLayer) {\n content += \"}\";\n }\n if (item[2]) {\n content += \"}\";\n }\n if (item[4]) {\n content += \"}\";\n }\n return content;\n }).join(\"\");\n };\n\n // import a list of modules into the list\n list.i = function i(modules, media, dedupe, supports, layer) {\n if (typeof modules === \"string\") {\n modules = [[null, modules, undefined]];\n }\n var alreadyImportedModules = {};\n if (dedupe) {\n for (var k = 0; k < this.length; k++) {\n var id = this[k][0];\n if (id != null) {\n alreadyImportedModules[id] = true;\n }\n }\n }\n for (var _k = 0; _k < modules.length; _k++) {\n var item = [].concat(modules[_k]);\n if (dedupe && alreadyImportedModules[item[0]]) {\n continue;\n }\n if (typeof layer !== \"undefined\") {\n if (typeof item[5] === \"undefined\") {\n item[5] = layer;\n } else {\n item[1] = \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\").concat(item[1], \"}\");\n item[5] = layer;\n }\n }\n if (media) {\n if (!item[2]) {\n item[2] = media;\n } else {\n item[1] = \"@media \".concat(item[2], \" {\").concat(item[1], \"}\");\n item[2] = media;\n }\n }\n if (supports) {\n if (!item[4]) {\n item[4] = \"\".concat(supports);\n } else {\n item[1] = \"@supports (\".concat(item[4], \") {\").concat(item[1], \"}\");\n item[4] = supports;\n }\n }\n list.push(item);\n }\n };\n return list;\n};","\"use strict\";\n\nmodule.exports = function (url, options) {\n if (!options) {\n options = {};\n }\n if (!url) {\n return url;\n }\n url = String(url.__esModule ? url.default : url);\n\n // If url is already wrapped in quotes, remove them\n if (/^['\"].*['\"]$/.test(url)) {\n url = url.slice(1, -1);\n }\n if (options.hash) {\n url += options.hash;\n }\n\n // Should url be wrapped?\n // See https://drafts.csswg.org/css-values-3/#urls\n if (/[\"'() \\t\\n]|(%20)/.test(url) || options.needQuotes) {\n return \"\\\"\".concat(url.replace(/\"/g, '\\\\\"').replace(/\\n/g, \"\\\\n\"), \"\\\"\");\n }\n return url;\n};","\"use strict\";\n\nmodule.exports = function (item) {\n var content = item[1];\n var cssMapping = item[3];\n if (!cssMapping) {\n return content;\n }\n if (typeof btoa === \"function\") {\n var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(cssMapping))));\n var data = \"sourceMappingURL=data:application/json;charset=utf-8;base64,\".concat(base64);\n var sourceMapping = \"/*# \".concat(data, \" */\");\n return [content].concat([sourceMapping]).join(\"\\n\");\n }\n return [content].join(\"\\n\");\n};","\"use strict\";\n\nvar stylesInDOM = [];\nfunction getIndexByIdentifier(identifier) {\n var result = -1;\n for (var i = 0; i < stylesInDOM.length; i++) {\n if (stylesInDOM[i].identifier === identifier) {\n result = i;\n break;\n }\n }\n return result;\n}\nfunction modulesToDom(list, options) {\n var idCountMap = {};\n var identifiers = [];\n for (var i = 0; i < list.length; i++) {\n var item = list[i];\n var id = options.base ? item[0] + options.base : item[0];\n var count = idCountMap[id] || 0;\n var identifier = \"\".concat(id, \" \").concat(count);\n idCountMap[id] = count + 1;\n var indexByIdentifier = getIndexByIdentifier(identifier);\n var obj = {\n css: item[1],\n media: item[2],\n sourceMap: item[3],\n supports: item[4],\n layer: item[5]\n };\n if (indexByIdentifier !== -1) {\n stylesInDOM[indexByIdentifier].references++;\n stylesInDOM[indexByIdentifier].updater(obj);\n } else {\n var updater = addElementStyle(obj, options);\n options.byIndex = i;\n stylesInDOM.splice(i, 0, {\n identifier: identifier,\n updater: updater,\n references: 1\n });\n }\n identifiers.push(identifier);\n }\n return identifiers;\n}\nfunction addElementStyle(obj, options) {\n var api = options.domAPI(options);\n api.update(obj);\n var updater = function updater(newObj) {\n if (newObj) {\n if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) {\n return;\n }\n api.update(obj = newObj);\n } else {\n api.remove();\n }\n };\n return updater;\n}\nmodule.exports = function (list, options) {\n options = options || {};\n list = list || [];\n var lastIdentifiers = modulesToDom(list, options);\n return function update(newList) {\n newList = newList || [];\n for (var i = 0; i < lastIdentifiers.length; i++) {\n var identifier = lastIdentifiers[i];\n var index = getIndexByIdentifier(identifier);\n stylesInDOM[index].references--;\n }\n var newLastIdentifiers = modulesToDom(newList, options);\n for (var _i = 0; _i < lastIdentifiers.length; _i++) {\n var _identifier = lastIdentifiers[_i];\n var _index = getIndexByIdentifier(_identifier);\n if (stylesInDOM[_index].references === 0) {\n stylesInDOM[_index].updater();\n stylesInDOM.splice(_index, 1);\n }\n }\n lastIdentifiers = newLastIdentifiers;\n };\n};","\"use strict\";\n\nvar memo = {};\n\n/* istanbul ignore next */\nfunction getTarget(target) {\n if (typeof memo[target] === \"undefined\") {\n var styleTarget = document.querySelector(target);\n\n // Special case to return head of iframe instead of iframe itself\n if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {\n try {\n // This will throw an exception if access to iframe is blocked\n // due to cross-origin restrictions\n styleTarget = styleTarget.contentDocument.head;\n } catch (e) {\n // istanbul ignore next\n styleTarget = null;\n }\n }\n memo[target] = styleTarget;\n }\n return memo[target];\n}\n\n/* istanbul ignore next */\nfunction insertBySelector(insert, style) {\n var target = getTarget(insert);\n if (!target) {\n throw new Error(\"Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.\");\n }\n target.appendChild(style);\n}\nmodule.exports = insertBySelector;","\"use strict\";\n\n/* istanbul ignore next */\nfunction insertStyleElement(options) {\n var element = document.createElement(\"style\");\n options.setAttributes(element, options.attributes);\n options.insert(element, options.options);\n return element;\n}\nmodule.exports = insertStyleElement;","\"use strict\";\n\n/* istanbul ignore next */\nfunction setAttributesWithoutAttributes(styleElement) {\n var nonce = typeof __webpack_nonce__ !== \"undefined\" ? __webpack_nonce__ : null;\n if (nonce) {\n styleElement.setAttribute(\"nonce\", nonce);\n }\n}\nmodule.exports = setAttributesWithoutAttributes;","\"use strict\";\n\n/* istanbul ignore next */\nfunction apply(styleElement, options, obj) {\n var css = \"\";\n if (obj.supports) {\n css += \"@supports (\".concat(obj.supports, \") {\");\n }\n if (obj.media) {\n css += \"@media \".concat(obj.media, \" {\");\n }\n var needLayer = typeof obj.layer !== \"undefined\";\n if (needLayer) {\n css += \"@layer\".concat(obj.layer.length > 0 ? \" \".concat(obj.layer) : \"\", \" {\");\n }\n css += obj.css;\n if (needLayer) {\n css += \"}\";\n }\n if (obj.media) {\n css += \"}\";\n }\n if (obj.supports) {\n css += \"}\";\n }\n var sourceMap = obj.sourceMap;\n if (sourceMap && typeof btoa !== \"undefined\") {\n css += \"\\n/*# sourceMappingURL=data:application/json;base64,\".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), \" */\");\n }\n\n // For old IE\n /* istanbul ignore if */\n options.styleTagTransform(css, styleElement, options.options);\n}\nfunction removeStyleElement(styleElement) {\n // istanbul ignore if\n if (styleElement.parentNode === null) {\n return false;\n }\n styleElement.parentNode.removeChild(styleElement);\n}\n\n/* istanbul ignore next */\nfunction domAPI(options) {\n if (typeof document === \"undefined\") {\n return {\n update: function update() {},\n remove: function remove() {}\n };\n }\n var styleElement = options.insertStyleElement(options);\n return {\n update: function update(obj) {\n apply(styleElement, options, obj);\n },\n remove: function remove() {\n removeStyleElement(styleElement);\n }\n };\n}\nmodule.exports = domAPI;","\"use strict\";\n\n/* istanbul ignore next */\nfunction styleTagTransform(css, styleElement) {\n if (styleElement.styleSheet) {\n styleElement.styleSheet.cssText = css;\n } else {\n while (styleElement.firstChild) {\n styleElement.removeChild(styleElement.firstChild);\n }\n styleElement.appendChild(document.createTextNode(css));\n }\n}\nmodule.exports = styleTagTransform;","module.exports = __WEBPACK_EXTERNAL_MODULE__53__;","module.exports = __WEBPACK_EXTERNAL_MODULE__941__;","module.exports = __WEBPACK_EXTERNAL_MODULE__104__;","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\tid: moduleId,\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n// expose the modules object (__webpack_modules__)\n__webpack_require__.m = __webpack_modules__;\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","__webpack_require__.b = (typeof document !== 'undefined' && document.baseURI) || self.location.href;\n\n// object to store loaded and loading chunks\n// undefined = chunk not loaded, null = chunk preloaded/prefetched\n// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded\nvar installedChunks = {\n\t792: 0\n};\n\n// no chunk on demand loading\n\n// no prefetching\n\n// no preloaded\n\n// no HMR\n\n// no HMR manifest\n\n// no on chunks loaded\n\n// no jsonp function","__webpack_require__.nc = undefined;","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./webidControl.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./webidControl.css\";\n export default content && content.locals ? content.locals : undefined;\n","/* eslint-disable no-console */\n\nexport function log (...args) {\n console.log(...args)\n}\n\nexport function warn (...args) {\n console.warn(...args)\n}\n\nexport function error (...args) {\n console.error(...args)\n}\n\nexport function trace (...args) {\n console.trace(...args)\n}\n","// Render a control to record the webids we have for this agent\n\nimport * as UI from 'solid-ui'\nimport { store } from 'solid-logic'\nimport { updateMany } from './contactLogic'\nimport * as $rdf from 'rdflib'\nimport './styles/webidControl.css'\nimport * as debug from './debug'\n\nconst ns = UI.ns\nconst widgets = UI.widgets\nconst utils = UI.utils\nconst kb = store\n\nconst wikidataClasses = widgets.publicData.wikidataClasses // @@ move to solid-logic\nconst wikidataParameters = widgets.publicData.wikidataParameters // @@ move to solid-logic\n\nconst WEBID_NOUN = 'WebID'\nconst PUBLICID_NOUN = 'WikiData link'\nconst DOWN_ARROW = UI.icons.iconBase + 'noun_1369241.svg'\nconst UP_ARROW = UI.icons.iconBase + 'noun_1369237.svg'\n\n/// ///////////////////////// Logic\n\nexport async function addWebIDToContacts (person, webid, urlType, kb) {\n /*\n if (!webid.startsWith('https:')) { /// @@ well we will have other protcols like DID\n if (webid.startsWith('http://') {\n webid = 'https:' + webid.slice(5) // @@ No, data won't match in store. Add the 's' on fetch()\n } else {\n throw new Error('Does not look like a webid, must start with https: ' + webid)\n }\n }\n */\n\n // check this is a url\n try {\n // eslint-disable-next-line no-unused-vars\n const _url = new URL(webid)\n } catch (error) {\n throw new Error(`${WEBID_NOUN}: ${webid} is not a valid url.`)\n }\n\n // create a person's webID\n debug.log(`Adding to ${person} a ${WEBID_NOUN}: ${webid}.`)\n const vcardURLThing = kb.bnode()\n const insertables = [\n $rdf.st(person, ns.vcard('url'), vcardURLThing, person.doc()),\n $rdf.st(vcardURLThing, ns.rdf('type'), urlType, person.doc()),\n $rdf.st(vcardURLThing, ns.vcard('value'), webid, person.doc())\n ]\n // insert WebID in groups\n // replace person with WebID in vcard:hasMember (WebID may already exist)\n // insert owl:sameAs\n const groups = kb.each(null, ns.vcard('hasMember'), person)\n let deletables = []\n groups.forEach(group => {\n deletables = deletables.concat(kb.statementsMatching(group, ns.vcard('hasMember'), person, group.doc()))\n insertables.push($rdf.st(group, ns.vcard('hasMember'), kb.sym(webid), group.doc())) // May exist; do we need to check?\n insertables.push($rdf.st(kb.sym(webid), ns.owl('sameAs'), person, group.doc()))\n })\n try {\n await updateMany(deletables, insertables)\n } catch (err) { throw new Error(`Could not create webId ${WEBID_NOUN}: ${webid}.`) }\n}\n\nexport async function removeWebIDFromContacts (person, webid, urlType, kb) {\n debug.log(`Removing from ${person} their ${WEBID_NOUN}: ${webid}.`)\n\n // remove webID from card\n const existing = kb.each(person, ns.vcard('url'), null, person.doc())\n .filter(urlObject => kb.holds(urlObject, ns.rdf('type'), urlType, person.doc()))\n .filter(urlObject => kb.holds(urlObject, ns.vcard('value'), webid, person.doc()))\n if (!existing.length) {\n throw new Error(`Person ${person} does not have ${WEBID_NOUN} ${webid}.`)\n }\n const vcardURLThing = existing[0]\n const deletables = [\n $rdf.st(person, ns.vcard('url'), vcardURLThing, person.doc()),\n $rdf.st(vcardURLThing, ns.rdf('type'), urlType, person.doc()),\n $rdf.st(vcardURLThing, ns.vcard('value'), webid, person.doc())\n ]\n await kb.updater.update(deletables, [])\n\n // remove webIDs from groups\n const groups = kb.each(null, ns.vcard('hasMember'), kb.sym(webid))\n let removeFromGroups = []\n const insertInGroups = []\n groups.forEach(async group => {\n removeFromGroups = removeFromGroups.concat(kb.statementsMatching(kb.sym(webid), ns.owl('sameAs'), person, group.doc()))\n insertInGroups.push($rdf.st(group, ns.vcard('hasMember'), person, group.doc()))\n if (kb.statementsMatching(kb.sym(webid), ns.owl('sameAs'), null, group.doc()).length < 2) {\n removeFromGroups = removeFromGroups.concat(kb.statementsMatching(group, ns.vcard('hasMember'), kb.sym(webid), group.doc()))\n }\n })\n await updateMany(removeFromGroups, insertInGroups)\n}\n\n// Trace things the same as this - other IDs for same thing\n// returns as array of node\nfunction getSameAs (kb, thing, doc) { // Should this recurse?\n const found = new Set()\n const agenda = new Set([thing.uri])\n\n while (agenda.size) {\n const uri = Array.from(agenda)[0] // clumsy\n agenda.delete(uri)\n if (found.has(uri)) continue\n found.add(uri)\n const node = kb.sym(uri)\n kb.each(node, ns.owl('sameAs'), null, doc)\n .concat(kb.each(null, ns.owl('sameAs'), node, doc))\n .forEach(next => {\n debug.log(' OWL sameAs found ' + next)\n agenda.add(next.uri)\n })\n kb.each(node, ns.schema('sameAs'), null, doc)\n .concat(kb.each(null, ns.schema('sameAs'), node, doc))\n .forEach(next => {\n debug.log(' Schema sameAs found ' + next)\n agenda.add(next.uri)\n })\n }\n found.delete(thing.uri) // don't want the one we knew about\n return Array.from(found).map(uri => kb.sym(uri)) // return as array of nodes\n}\n\n// find person webIDs\nexport function getPersonas (kb, person) {\n const lits = vcardWebIDs(kb, person).concat(getSameAs(kb, person, person.doc()))\n const strings = new Set(lits.map(lit => lit.value)) // remove dups\n const personas = [...strings].map(uri => kb.sym(uri)) // The UI tables do better with Named Nodes than Literals\n personas.sort() // for repeatability\n personas.filter(x => !x.sameTerm(person))\n return personas\n}\n\nexport function vcardWebIDs (kb, person, urlType) {\n return kb.each(person, ns.vcard('url'), null, person.doc())\n .filter(urlObject => kb.holds(urlObject, ns.rdf('type'), urlType, person.doc()))\n .map(urlObject => kb.any(urlObject, ns.vcard('value'), null, person.doc()))\n .filter(x => !!x) // remove nulls\n}\n\nexport function isOrganization (agent) {\n const doc = agent.doc()\n return kb.holds(agent, ns.rdf('type'), ns.vcard('Organization'), doc) ||\n kb.holds(agent, ns.rdf('type'), ns.schema('Organization'), doc)\n}\n/// ////////////////////////////////////////////////////////////// UI\n\n// Utility function to render another different pane\n\nexport function renderNamedPane (dom, subject, paneName, dataBrowserContext) {\n const p = dataBrowserContext.session.paneRegistry.byName(paneName)\n const d = p.render(subject, dataBrowserContext) // @@@ change some bits of context!\n d.classList.add('namedPane')\n return d\n}\n\nexport async function renderWebIdControl (person, dataBrowserContext) {\n const options = {\n longPrompt: `Link to a ${WEBID_NOUN}?`,\n idNoun: WEBID_NOUN,\n urlType: ns.vcard('WebID')\n }\n return renderIdControl(person, dataBrowserContext, options)\n}\n\nexport async function renderPublicIdControl (person, dataBrowserContext) {\n let orgClass = kb.sym('http://www.wikidata.org/wiki/Q43229')\n for (const classId in wikidataClasses) {\n if (kb.holds(person, ns.rdf('type'), ns.schema(classId), person.doc())) {\n orgClass = kb.sym(wikidataClasses[classId])\n debug.log(` renderPublicIdControl bingo: ${classId} -> ${orgClass}`)\n }\n }\n const options = {\n longPrompt: `Add a ${PUBLICID_NOUN}?`,\n idNoun: PUBLICID_NOUN,\n urlType: ns.vcard('PublicId'),\n dbLookup: true,\n class: orgClass, // Organization\n queryParams: wikidataParameters\n }\n return renderIdControl(person, dataBrowserContext, options)\n}\n\n// The main control rendered by this module\nexport async function renderIdControl (person, dataBrowserContext, options) {\n // IDs which are as WebId in VCARD data\n // like :me vcard:hasURL [ a vcard:WebId; vcard:value <https://...foo> ]\n //\n // Display the data about x specifically stored at x.doc()\n // in a fold-away thing\n //\n function renderPersona (dom, persona, kb) {\n function profileOpenHandler (_event) {\n profileIsVisible = !profileIsVisible\n main.classList.toggle('collapsed', !profileIsVisible)\n openButton.children[0].src = profileIsVisible ? UP_ARROW : DOWN_ARROW // @@ fragile\n openButton.setAttribute('aria-expanded', profileIsVisible ? 'true' : 'false')\n openButton.setAttribute('aria-label', profileIsVisible ? 'Collapse profile' : 'Expand profile')\n }\n function renderNewRow (webidObject) {\n const webid = new $rdf.Literal(webidObject.uri)\n async function deleteFunction () {\n try {\n await removeWebIDFromContacts(person, webid, options.urlType, kb)\n } catch (err) {\n debug.error(`Error removing Id ${webid} from ${person}: ${err}`)\n div.appendChild(widgets.errorMessageBlock(dom, 'Error removing WebId from profile. If it persists, contact admin.'))\n }\n await refreshWebIDTable()\n }\n const isWebId = options.urlType.sameTerm(ns.vcard('WebID'))\n const delFunParam = options.editable ? deleteFunction : null\n const opts = { deleteFunction: delFunParam, draggable: true }\n if (isWebId) {\n opts.title = webidObject.uri.split('/')[2]\n opts.image = widgets.faviconOrDefault(dom, webidObject.site()) // just for domain\n }\n const row = widgets.personTR(dom, UI.ns.foaf('knows'), webidObject, opts)\n if (isWebId) {\n row.children[1].textConent = opts.title // @@ will be overwritten\n row.classList.add('personaRow--webid')\n }\n row.classList.add('personaRow')\n return row\n }\n\n const div = dom.createElement('div')\n div.classList.add('fullWidth')\n const personaTable = div.appendChild(dom.createElement('table'))\n personaTable.classList.add('fullWidth')\n const nav = personaTable.appendChild(renderNewRow(persona))\n nav.classList.add('fullWidth')\n const mainRow = personaTable.appendChild(dom.createElement('tr'))\n const mainCell = mainRow.appendChild(dom.createElement('td'))\n mainCell.setAttribute('colspan', 3)\n let main\n\n let profileIsVisible = true\n\n const rhs = nav.children[2]\n const openButton = rhs.appendChild(widgets.button(dom, DOWN_ARROW, 'View', profileOpenHandler))\n openButton.classList.add('personaOpenButton')\n openButton.setAttribute('aria-expanded', 'true')\n openButton.setAttribute('aria-label', 'Collapse profile')\n const paneName = isOrganization(person) || isOrganization(persona) ? 'profile' : 'profile' // was default for org\n\n widgets.publicData.loadPublicDataThing(kb, person, persona).then(_resp => {\n // loadPublicDataThing(kb, person, persona).then(_resp => {\n try {\n main = renderNamedPane(dom, persona, paneName, dataBrowserContext)\n main.classList.add('fullWidth')\n // main.style.visibility = 'collapse'\n mainCell.appendChild(main)\n } catch (err) {\n debug.error('Error displaying persona ' + persona + '. Stack: ' + err)\n main = widgets.errorMessageBlock(dom, 'Error displaying profile. If it persists, contact admin.')\n mainCell.appendChild(main)\n }\n }, err => {\n debug.error('Error loading persona ' + persona + '. Stack: ' + err)\n main = widgets.errorMessageBlock(dom, 'Error loading profile. If it persists, contact admin.')\n mainCell.appendChild(main)\n })\n return div\n } // renderPersona\n\n async function refreshWebIDTable () {\n const personas = getPersonas(kb, person)\n utils.syncTableToArrayReOrdered(profileArea, personas, persona => renderPersona(dom, persona, kb))\n }\n async function addOneIdAndRefresh (person, webid) {\n try {\n await addWebIDToContacts(person, webid, options.urlType, kb)\n } catch (err) {\n debug.error('Error adding webId ' + webid + ' to ' + person + '. Stack: ' + err)\n div.appendChild(widgets.errorMessageBlock(dom, 'This is not a valid WebID.'))\n }\n await refreshWebIDTable()\n }\n\n const { dom } = dataBrowserContext\n options = options || {}\n options.editable = kb.updater.editable(person.doc().uri, kb)\n const div = dom.createElement('div')\n div.classList.add('webidControl')\n\n if (getPersonas(kb, person).length === 0 && !options.editable) {\n div.classList.add('hidden')\n return div // No point listing an empty list you can't change\n }\n\n const h3 = div.appendChild(dom.createElement('h3'))\n h3.textContent = 'Link to a ' + options.idNoun\n h3.classList.add('contactPanedHeading')\n\n const table = div.appendChild(dom.createElement('table'))\n table.classList.add('fullWidth')\n\n if (options.editable) { // test\n const barOptions = {\n editable: options.editable,\n manualURIEntry: true, // introduced in solid-ui 2.4.2\n idNoun: options.idNoun,\n dbLookup: options.dbLookup\n }\n const acOptions = {\n queryParams: options.queryParams || wikidataParameters,\n targetClass: options.class\n }\n try {\n div.appendChild(await widgets.renderAutocompleteControl(dom, person, barOptions, acOptions, addOneIdAndRefresh))\n } catch (err) {\n debug.error('Render Autocomplete Control failed. Stack:', err)\n div.appendChild(widgets.errorMessageBlock(dom, 'Error rendering autocomplete. If it persists, contact admin.'))\n }\n }\n const profileArea = div.appendChild(dom.createElement('div'))\n await refreshWebIDTable()\n\n return div\n}\n","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./localUtils.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./localUtils.css\";\n export default content && content.locals ? content.locals : undefined;\n","import * as debug from './debug'\nimport * as UI from 'solid-ui'\nimport { store } from 'solid-logic'\nimport './styles/localUtils.css'\n\nconst kb = store\nconst ns = UI.ns\nlet dom\n\nexport function setDom (d) {\n dom = d\n}\n\n// ---------- Accessible modal dialog helpers ----------\n// This code was generated by Generative AI (Raptor mini in GitHub Copilot) based on the following prompt:\n// Regarding accessibility, how should I replace alert()/confirm() with accessible modal dialogs?\n// Let us implement the modals in the localUtils.\n\n// alert()/confirm(). The implementation ensures focus trapping, keyboard\n// support, and hides the rest of the page from screen readers while the\n// dialog is visible.\n\nlet modalOverlay = null\nlet previousFocus = null\n\nfunction ensureModalOverlay () {\n // if we previously created an overlay but it was removed from the document\n // (tests clear body), rebuild it. Checking presence ensures our reference\n // doesn't point at a detached element.\n if (modalOverlay && document.body.contains(modalOverlay)) return modalOverlay\n // otherwise drop stale reference and create a new element\n modalOverlay = null\n // overlay container\n modalOverlay = dom.createElement('div')\n modalOverlay.id = 'contacts-modal'\n modalOverlay.className = 'focus-trap hidden'\n modalOverlay.setAttribute('role', 'presentation')\n\n modalOverlay.innerHTML = `\n <div class=\"modal\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"modal-title\" aria-describedby=\"modal-desc\">\n <h2 id=\"modal-title\"></h2>\n <div id=\"modal-desc\"></div>\n <div id=\"modal-buttons\"></div>\n </div>\n `\n\n document.body.appendChild(modalOverlay)\n\n // keyboard handling (esc/tab)\n modalOverlay.addEventListener('keydown', e => {\n if (e.key === 'Escape') {\n e.stopPropagation()\n // simulate cancel if available\n const cancelBtn = modalOverlay.querySelector('button[data-cancel]')\n if (cancelBtn) cancelBtn.click()\n else closeModal(false)\n } else if (e.key === 'Tab') {\n // simple focus trap: cycle through focusable elements inside overlay\n const focusable = Array.from(modalOverlay.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])')).filter(el => !el.hasAttribute('disabled'))\n if (focusable.length === 0) return\n const idx = focusable.indexOf(document.activeElement)\n if (e.shiftKey) {\n if (idx === 0) {\n focusable[focusable.length - 1].focus()\n e.preventDefault()\n }\n } else {\n if (idx === focusable.length - 1) {\n focusable[0].focus()\n e.preventDefault()\n }\n }\n }\n })\n\n return modalOverlay\n}\n\nfunction hideSiblings (hide) {\n const siblings = Array.from(document.body.children).filter(c => c !== modalOverlay)\n siblings.forEach(el => {\n if (hide) el.setAttribute('aria-hidden', 'true')\n else el.removeAttribute('aria-hidden')\n })\n}\n\nfunction openModal ({ title, message, buttons }) {\n const overlay = ensureModalOverlay()\n previousFocus = document.activeElement\n hideSiblings(true)\n overlay.classList.remove('hidden')\n\n overlay.querySelector('#modal-title').textContent = title || ''\n const descEl = overlay.querySelector('#modal-desc')\n if (typeof message === 'string') {\n descEl.textContent = message\n } else {\n // allow passing nodes\n descEl.innerHTML = ''\n descEl.appendChild(message)\n }\n\n const btnContainer = overlay.querySelector('#modal-buttons')\n btnContainer.innerHTML = ''\n\n return new Promise(resolve => {\n buttons.forEach(btn => {\n const b = dom.createElement('button')\n b.setAttribute('type', 'button')\n b.textContent = btn.label\n if (btn.primary) b.classList.add('btn-primary')\n if (btn.cancel) b.setAttribute('data-cancel', 'true')\n b.addEventListener('click', () => {\n closeModal(btn.value)\n resolve(btn.value)\n })\n btnContainer.appendChild(b)\n })\n // focus first button\n const first = btnContainer.querySelector('button')\n if (first) first.focus()\n })\n}\n\nfunction closeModal (result) {\n if (modalOverlay) {\n modalOverlay.classList.add('hidden')\n hideSiblings(false)\n if (previousFocus && previousFocus.focus) previousFocus.focus()\n }\n}\n\n/**\n * Show an alert-style modal that has a single OK button.\n * @param {string} message\n * @param {string} [title]\n * @returns {Promise<true>}\n */\nexport function alertDialog (message, title = 'Information') {\n return openModal({\n title,\n message,\n buttons: [{ label: 'OK', value: true, primary: true }]\n })\n}\n\n/**\n * Show a confirm-style modal returning a boolean.\n * @param {string} message\n * @param {string} [title]\n * @returns {Promise<boolean>}\n */\nexport function confirmDialog (message, title = 'Confirm') {\n return openModal({\n title,\n message,\n buttons: [\n { label: 'Cancel', value: false, cancel: true },\n { label: 'OK', value: true, primary: true }\n ]\n })\n}\n\n// ---------- end of modal helpers ----------\n\n/**\n * Normalize group URIs to ensure consistent representation.\n * Groups should be referenced with fragment #this, e.g., ...Group/AnotherGroup.ttl#this\n * If a group URI ends with .ttl (without #this), add #this\n * @param {string} uri - The group URI to normalize\n * @returns {string} The normalized group URI\n */\nexport function normalizeGroupUri (uri) {\n if (uri && uri.endsWith('.ttl')) {\n return uri + '#this'\n }\n return uri\n}\n\nexport function complain (div, d, message) {\n div.appendChild(UI.widgets.errorMessageBlock(d, message, 'pink'))\n}\n\nexport function getSameAs (kb, item, doc) {\n return kb.each(item, ns.owl('sameAs'), null, doc).concat(\n kb.each(null, ns.owl('sameAs'), item, doc))\n}\n// For deleting an addressbook sub-folder eg person - use with care!\n// @@ move to solid-logic\nexport function deleteRecursive (kb, folder) {\n return new Promise(function (resolve, reject) {\n kb.fetcher.load(folder).then(function () {\n const promises = kb.each(folder, ns.ldp('contains')).map(file => {\n if (kb.holds(file, ns.rdf('type'), ns.ldp('BasicContainer'))) {\n return deleteRecursive(kb, file)\n } else {\n debug.log('Recursive delete - we delete file ' + file.uri)\n return kb.fetcher.webOperation('DELETE', file.uri)\n }\n })\n debug.log('Recursive delete - we delete folder ' + folder.uri)\n promises.push(kb.fetcher.webOperation('DELETE', folder.uri))\n Promise.all(promises).then(_res => {\n resolve()\n }).catch(reject)\n }).catch(reject)\n })\n}\n\n// In a LDP work, deletes the whole document describing a thing\n// plus patch out ALL mentiosn of it! Use with care!\n// beware of other data picked up from other places being smushed\n// together and then deleted.\nexport async function deleteThingAndDoc (x) {\n const name = nameFor(x)\n if (!(await confirmDialog('Really DELETE ' + name + '?'))) {\n throw new Error('User cancelled contact deletion')\n }\n debug.log('deleteThingAndDoc - to be deleted ' + x)\n const ds = kb.statementsMatching(x).concat(kb.statementsMatching(undefined, undefined, x))\n try {\n await kb.updater.updateMany(ds)\n await kb.fetcher.delete(x.doc())\n debug.log('deleteThingAndDoc - deleted')\n } catch (err) {\n debug.error('Error deleting ' + x + '. Stack: ' + err)\n throw new Error('An error occured while deleting.')\n }\n}\n\nexport function compareForSort (self, other) {\n let s = nameFor(self)\n let o = nameFor(other)\n if (s && o) {\n s = s.toLowerCase()\n o = o.toLowerCase()\n if (s > o) return 1\n if (s < o) return -1\n }\n if (self.uri > other.uri) return 1\n if (self.uri < other.uri) return -1\n return 0\n}\n\n// organization-name is a hack for Mac records with no FN which is mandatory.\nexport function nameFor (x) {\n const name =\n kb.any(x, ns.vcard('fn')) ||\n kb.any(x, ns.foaf('name')) ||\n kb.any(x, ns.vcard('organization-name'))\n return name ? name.value : '???'\n}\n\n/**\n * Prevent keyboard tabbing into labels/label-like links created by rdflib/solid-ui forms.\n * @param {HTMLElement} root\n */\nexport function skipLabelsFromTabbing (root) {\n // Many Solid-UI forms render field labels as focusable links (hrefs).\n // Make sure keyboard tabbing skips these label links entirely.\n const selectors = [\n 'label',\n '.formFieldName a',\n '.classifierBox-label a',\n '.choiceBox-label a',\n '.label a',\n // Skip focusable label-like links created by Solid-UI forms, including the vcard note link\n 'a[href=\"http://www.w3.org/2006/vcard/ns#note\"]',\n 'a[href$=\"#note\"]',\n ].join(', ')\n\n // Some environments have NodeLists without forEach (e.g., older Safari).\n const nodes = root?.querySelectorAll?.(selectors)\n if (!nodes) return\n\n Array.from(nodes).forEach(el => {\n // Some browsers may return null for tabIndex, and some elements may not\n // expose tabIndex at all (e.g., SVG elements), so guard before setting.\n if (typeof el.tabIndex === 'number' && el.tabIndex !== -1) {\n el.tabIndex = -1\n }\n // Ensure those label links are not announced as focusable elements\n if (el.getAttribute('aria-hidden') !== 'true') {\n el.setAttribute('aria-hidden', 'true')\n }\n })\n}\n\nexport function isAWebID (subject) {\n const t = kb.findTypeURIs(subject.doc())\n return !!t[ns.foaf('PersonalProfileDocument').uri]\n}\n\n// Make the layout stack vertically when the containing pane gets narrow\nexport function setupResponsiveStacking (paneDiv, breakpoint = 900) {\n function updateFromPane () {\n const width = paneDiv.getBoundingClientRect().width\n const isNarrow = width <= breakpoint\n // Always track viewport fallback even if pane is not in DOM yet\n const viewportNarrow = (typeof window !== 'undefined' && typeof window.matchMedia === 'function')\n ? window.matchMedia('(max-width: ' + breakpoint + 'px)').matches\n : false\n\n if (width > 0) {\n paneDiv.classList.toggle('contactPane--narrow', isNarrow)\n paneDiv.dataset.paneWidth = Math.round(width).toString()\n paneDiv.dataset.paneNarrow = isNarrow ? 'true' : 'false'\n } else {\n // If not inserted yet, apply viewport mode until placed.\n paneDiv.classList.toggle('contactPane--narrow', viewportNarrow)\n paneDiv.dataset.paneWidth = '0'\n paneDiv.dataset.paneNarrow = viewportNarrow ? 'true' : 'false'\n }\n\n paneDiv.dataset.viewportNarrow = viewportNarrow ? 'true' : 'false'\n\n return isNarrow\n }\n\n function updateFromViewport () {\n const isNarrow = (typeof window !== 'undefined' && typeof window.matchMedia === 'function')\n ? window.matchMedia('(max-width: ' + breakpoint + 'px)').matches\n : false\n paneDiv.classList.toggle('contactPane--narrow', isNarrow)\n paneDiv.dataset.viewportNarrow = isNarrow ? 'true' : 'false'\n return isNarrow\n }\n\n const resizeObserverAvailable = typeof ResizeObserver !== 'undefined'\n if (resizeObserverAvailable) {\n const ro = new ResizeObserver(() => updateFromPane())\n ro.observe(paneDiv)\n }\n\n if (typeof window !== 'undefined' && typeof window.addEventListener === 'function') {\n window.addEventListener('resize', () => {\n updateFromPane()\n updateFromViewport()\n })\n }\n\n // Initial state\n function ensureInitialUpdate () {\n // Call both updaters for their side effects (setting dataset attributes).\n // Return values are intentionally discarded — ESLint-safe.\n updateFromPane()\n updateFromViewport()\n // If we are not in the document yet, re-run until connected\n if (!paneDiv.isConnected) {\n requestAnimationFrame(ensureInitialUpdate)\n }\n }\n\n ensureInitialUpdate()\n}\n","import * as UI from 'solid-ui'\nimport * as $rdf from 'rdflib'\nimport { store } from 'solid-logic'\nimport { getPersonas } from './webidControl'\nimport * as debug from './debug'\nimport { getSameAs, confirmDialog, alertDialog } from './localUtils'\n\nconst ns = UI.ns\nconst utils = UI.utils\nconst kb = store\nconst updater = kb.updater\n\n/** Perform updates on more than one document @@ Move to rdflib!\n*/\nexport async function updateMany (deletions, insertions = []) {\n const docs = deletions.concat(insertions).map(st => st.why)\n const uniqueDocs = []\n docs.forEach(doc => {\n if (!uniqueDocs.find(uniqueDoc => uniqueDoc.equals(doc))) uniqueDocs.push(doc)\n })\n const updates = uniqueDocs.map(doc =>\n kb.updater.update(deletions.filter(st => st.why.sameTerm(doc)),\n insertions.filter(st => st.why.sameTerm(doc))))\n return Promise.all(updates)\n}\n\n/** Add a new person to the web data\n*\n* adds them to the given groups as well.\n* @returns {NamedNode} the person\n*/\nexport async function saveNewContact (book, name, selectedGroups, klass) {\n await kb.fetcher.load(book.doc())\n const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))\n\n const uuid = utils.genUuid()\n const person = kb.sym(\n book.dir().uri + 'Person/' + uuid + '/index.ttl#this'\n )\n const doc = person.doc()\n\n // Set of statements to different files\n const agenda = [\n // Patch the main index to add the person\n $rdf.st(person, ns.vcard('inAddressBook'), book, nameEmailIndex), // The people index\n $rdf.st(person, ns.vcard('fn'), name, nameEmailIndex),\n // The new person file\n $rdf.st(person, ns.vcard('fn'), name, doc),\n $rdf.st(person, ns.rdf('type'), klass, doc),\n\n $rdf.st(doc, ns.dct('created'), new Date(), doc) // Note when created - useful for triaging later\n // Note this is propert of the file -- not when the person was created!\n ]\n\n // `selectedGroups` may be an array (older callers) or an object map\n // (contactsPane.js tracks it as `{ uri: true }`). Normalize and make sure\n // at least one group is selected before proceeding – otherwise we return\n // `undefined` and the caller must handle it.\n const groups = Array.isArray(selectedGroups)\n ? selectedGroups\n : Object.keys(selectedGroups || {})\n\n if (groups.length > 0) {\n for (const gu of groups) {\n const g = kb.sym(gu)\n const gd = g.doc()\n agenda.push(\n $rdf.st(g, ns.vcard('hasMember'), person, gd),\n $rdf.st(person, ns.vcard('fn'), name, gd)\n )\n }\n } else {\n alertDialog('Must be a member of at least one group. Please select or create a group.')\n return // caller should check for undefined result\n }\n\n try {\n await updater.updateMany([], agenda)\n } catch (e) {\n debug.error('Cannot add group membership for ' + person + '. Stack:' + e)\n throw new Error('Save new contact')\n }\n return person\n}\n\nexport function sanitizeToAlpha (name) { // https://mathiasbynens.be/notes/es6-unicode-regex\n const n2 = name.replace(/\\W/gu, '_') // Anything which is not a unicode word characeter\n return n2.replace(/_+/g, '_') // https://www.regular-expressions.info/shorthand.html\n}\n\n/** Write new group to web\n * Creates an empty new group file and adds it to the index\n * @returns group\n*/\nexport async function saveNewGroup (book, name) {\n await kb.fetcher.load(book.doc())\n const gix = kb.any(book, ns.vcard('groupIndex'))\n\n const gname = sanitizeToAlpha(name)\n const group = kb.sym(book.dir().uri + 'Group/' + gname + '.ttl#this')\n const doc = group.doc()\n // debug.log(' New group will be: ' + group + '\\n')\n try {\n await kb.fetcher.load(gix)\n } catch (err) {\n throw new Error('Error loading group index!' + gix.uri + ': ' + err)\n }\n if (kb.holds(book, ns.vcard('includesGroup'), group, gix)) {\n return group // Already exists\n }\n const insertTriples = [\n $rdf.st(book, ns.vcard('includesGroup'), group, gix),\n $rdf.st(group, ns.rdf('type'), ns.vcard('Group'), gix),\n $rdf.st(group, ns.vcard('fn'), name, gix)\n ]\n try {\n await updater.update([], insertTriples)\n } catch (e) {\n throw new Error('Could not update group index ' + e) // fail\n }\n\n const triples = [\n $rdf.st(book, ns.vcard('includesGroup'), group, doc), // Pointer back to book\n $rdf.st(group, ns.rdf('type'), ns.vcard('Group'), doc),\n $rdf.st(group, ns.vcard('fn'), name, doc)\n ]\n try {\n await updater.update([], triples)\n } catch (err) {\n throw new Error('Could not update group file: ' + err) // fail\n }\n return group\n}\n\nexport async function addPersonToGroup (thing, group) {\n const toBeFetched = [thing.doc(), group.doc()]\n try {\n await kb.fetcher.load(toBeFetched)\n } catch (e) {\n debug.error('Error adding ' + thing + ' to group ' + group + '. Stack: ' + e)\n throw new Error('Error adding to group.')\n }\n\n const types = kb.findTypeURIs(thing)\n\n if (!(ns.vcard('Individual').uri in types ||\n ns.vcard('Organization').uri in types)) {\n debug.warn('Thing ' + thing + ' is not an Individual or Organization, but has types: ' + Object.keys(types))\n alertDialog('You are trying to add something else than an individual or organization.')\n return\n }\n let pname = kb.any(thing, ns.vcard('fn'))\n const gname = kb.any(group, ns.vcard('fn'))\n if (!pname) {\n debug.warn('Thing ' + thing + ' has no vcard:fn')\n alertDialog('What you are trying to add seems to have no full name.')\n return\n }\n const already = kb.holds(thing, ns.vcard('fn'), null, group.doc())\n if (already) {\n if (pname === '') pname = 'Contact'\n alertDialog(pname + ' already exists in group ' + gname + '.')\n return\n }\n const message = 'Add ' + pname + ' to group ' + gname + '?'\n if (!await confirmDialog(message)) return\n const ins = [\n $rdf.st(thing, ns.vcard('fn'), pname, group.doc())\n ]\n // find person webIDs and insert in vcard:hasMember\n const webIDs = getPersonas(kb, thing).map(webid => webid.value)\n if (webIDs.length) {\n webIDs.forEach(webid => {\n ins.push($rdf.st(kb.sym(webid), ns.owl('sameAs'), thing, group.doc()))\n ins.push($rdf.st(group, ns.vcard('hasMember'), kb.sym(webid), group.doc()))\n })\n } else {\n ins.push($rdf.st(group, ns.vcard('hasMember'), thing, group.doc()))\n }\n try {\n await updater.update([], ins)\n // to allow refresh of card groupList\n kb.fetcher.unload(group.doc())\n await kb.fetcher.load(group.doc())\n } catch (e) {\n debug.error('Error adding ' + thing + ' to group ' + group + '. Stack: ' + e)\n throw new Error('Error adding to group.')\n }\n return thing\n}\n\n/**\n * Find persons member of a group\n */\n\nexport function groupMembers (kb, group) {\n const a = kb.each(group, ns.vcard('hasMember'), null, group.doc())\n let b = []\n a.forEach(item => {\n /* const contacts = kb.each(item, ns.owl('sameAs'), null, group.doc())\n if (contacts.length) {\n if (!kb.any(contacts[0], ns.vard('fn'))) b = b.concat(item) // this is the old data model\n else b = b.concat(contacts)\n } else { b = b.concat(item) }\n b = b.concat(item) */\n\n // to keep compatibility with old data model\n // check if item is a contact, else it is a WebID and parse 'sameAs' for contacts\n b = kb.any(item, ns.vcard('fn'), null, group.doc()) ? b.concat(item) : b.concat(kb.each(item, ns.owl('sameAs'), null, group.doc()))\n })\n const strings = new Set(b.map(contact => contact.uri)) // remove dups\n b = [...strings].map(uri => kb.sym(uri))\n return b\n}\n\nexport function isLocal (group, item) {\n const tree = group.dir().dir().dir()\n const local = item.uri && item.uri.startsWith(tree.uri)\n // debug.log(` isLocal ${local} for ${item.uri} in group ${group} tree ${tree.uri}`)\n return local\n}\n\nexport async function getDataModelIssues (groups) {\n const del = []\n const ins = []\n groups.forEach(group => {\n const members = kb.each(group, ns.vcard('hasMember'), null, group.doc())\n members.forEach((member) => {\n const others = getSameAs(kb, member, group.doc())\n if (others.length && isLocal(group, member)) { // Problem: local ID used instead of webID\n for (const other of others) {\n if (!isLocal(group, other)) { // Let's use this one as the immediate member for CSS ACLs'\n // console.warn(`getDataModelIssues: Need to swap ${member} to ${other}`)\n del.push($rdf.st(group, ns.vcard('hasMember'), member, group.doc()))\n ins.push($rdf.st(group, ns.vcard('hasMember'), other, group.doc()))\n break\n }\n // debug.log('getDataModelIssues: ??? expected id not to be local ' + other)\n } // other\n } // if\n }) // member\n }) // next group\n return { del, ins }\n} // getDataModelIssues\n\n// Ends\n","import * as UI from 'solid-ui'\nimport { solidLogicSingleton } from 'solid-logic'\nimport * as $rdf from 'rdflib'\nimport { complain } from './localUtils'\nimport * as debug from './debug'\n\nconst { setACLUserPublic } = solidLogicSingleton.acl\n// const mime = require('mime-types')\n// const toolsPane0 = require('./toolsPane')\n// const toolsPane = toolsPane0.toolsPane\n\n// const ns = UI.ns\n// const utils = UI.utils\n\n// Mint a new address book\n\nexport function mintNewAddressBook (dataBrowserContext, context) {\n return new Promise(function (resolve, reject) {\n UI.login.ensureLoadedProfile(context).then(\n context => {\n // 20180713\n debug.log('Logged in as ' + context.me)\n const me = context.me\n\n const dom = context.dom\n const div = context.div\n const kb = dataBrowserContext.session.store\n const ns = UI.ns\n const newBase = context.newBase || context.newInstance.dir().uri\n const instanceClass = context.instanceClass || ns.vcard('AddressBook')\n\n if (instanceClass.sameTerm(ns.vcard('Group'))) {\n // Make a group not an address book\n const g =\n context.newInstance || kb.sym(context.newBase + 'index.ttl#this')\n const doc = g.doc()\n kb.add(g, ns.rdf('type'), ns.vcard('Group'), doc)\n kb.add(\n g,\n ns.vcard('fn'),\n context.instanceName || 'untitled group',\n doc\n ) // @@ write doc back\n kb.fetcher\n .putBack(doc, { contentType: 'text/turtle' })\n .then(function (_xhr) {\n resolve(context)\n })\n .catch(function (err) {\n debug.error('Failed to fetch new address book. Stack: ' + err)\n reject(\n new Error('Error creating document for new group ' + err)\n )\n })\n return\n }\n const appInstanceNoun = 'address book'\n\n let bookContents = `@prefix vcard: <http://www.w3.org/2006/vcard/ns#>.\n @prefix ab: <http://www.w3.org/ns/pim/ab#>.\n @prefix dc: <http://purl.org/dc/elements/1.1/>.\n @prefix xsd: <http://www.w3.org/2001/XMLSchema#>.\n\n <#this> a vcard:AddressBook;\n dc:title \"New address Book\";\n vcard:nameEmailIndex <people.ttl>;\n vcard:groupIndex <groups.ttl>.\n`\n\n bookContents +=\n '<#this> <http://www.w3.org/ns/auth/acl#owner> <' +\n me.uri +\n '>.\\n\\n'\n\n const newAppInstance = kb.sym(newBase + 'index.ttl#this')\n\n const toBeWritten = [\n {\n to: 'index.ttl',\n content: bookContents,\n contentType: 'text/turtle'\n },\n { to: 'groups.ttl', content: '', contentType: 'text/turtle' },\n { to: 'people.ttl', content: '', contentType: 'text/turtle' },\n { to: '', existing: true, aclOptions: { defaultForNew: true } }\n ]\n\n // @@ Ask user abut ACLs?\n\n //\n // @@ Add header to PUT If-None-Match: * to prevent overwrite\n //\n\n function claimSuccess (newAppInstance, appInstanceNoun) {\n // @@ delete or grey other stuff\n debug.log(`New ${appInstanceNoun} created at ${newAppInstance}`)\n const p = div.appendChild(dom.createElement('p'))\n p.classList.add('claimSuccess')\n p.innerHTML =\n 'Your <a href=\\'' +\n newAppInstance.uri +\n '\\'><b>new ' +\n appInstanceNoun +\n '</b></a> is ready. ' +\n '<br/><br/><a href=\\'' +\n newAppInstance.uri +\n '\\'>Go to new ' +\n appInstanceNoun +\n '</a>'\n const newContext = Object.assign(\n { newInstance: newAppInstance },\n context\n )\n resolve(newContext)\n }\n\n function doNextTask () {\n function checkOKSetACL (uri, ok) {\n if (!ok) {\n return reject(new Error('Error writing new file ' + task.to))\n }\n\n setACLUserPublic(dest, me, aclOptions)\n .then(() => doNextTask())\n .catch(err => {\n debug.error('Error setting access permissions for ' + task.to + '. Stack: ' + err)\n const message =\n 'Error setting access permissions for ' +\n task.to +\n '.'\n return reject(new Error(message))\n })\n }\n\n if (toBeWritten.length === 0) {\n claimSuccess(newAppInstance, appInstanceNoun)\n } else {\n var task = toBeWritten.shift() /* eslint-disable-line no-var */\n debug.log('Creating new file ' + task.to + ' in new instance ')\n var dest = $rdf.uri.join(task.to, newBase) /* eslint-disable-line no-var */\n var aclOptions = task.aclOptions || {} /* eslint-disable-line no-var */\n\n if ('content' in task) {\n kb.fetcher\n .webOperation('PUT', dest, {\n data: task.content,\n saveMetadata: true,\n contentType: task.contentType\n })\n .then(() => checkOKSetACL(dest, true))\n } else if ('existing' in task) {\n checkOKSetACL(dest, true)\n } else {\n reject(new Error('Copy not expected while buiding new app.'))\n // const from = task.from || task.to // default source to be same as dest\n // UI.widgets.webCopy(base + from, dest, task.contentType, checkOKSetACL)\n }\n }\n }\n doNextTask()\n },\n err => {\n // log in then\n debug.warn('Error logging in. Stack: ' + err)\n complain(context.div, context.dom, 'Please log in to create a new address book.')\n }\n )\n })\n}\n","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./mugshotGallery.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./mugshotGallery.css\";\n export default content && content.locals ? content.locals : undefined;\n","import * as UI from 'solid-ui'\nimport { store } from 'solid-logic'\nimport * as $rdf from 'rdflib'\nimport './styles/mugshotGallery.css'\nimport * as debug from './debug'\nimport { confirmDialog, alertDialog } from './localUtils'\n\n// Lightweight MIME helpers replacing the heavy mime-types/mime-db packages (~170 KiB)\nconst mimeMap = {\n 'image/png': 'png',\n 'image/jpeg': 'jpg',\n 'image/gif': 'gif',\n 'image/svg+xml': 'svg',\n 'image/webp': 'webp',\n 'image/bmp': 'bmp',\n 'image/tiff': 'tiff',\n 'application/pdf': 'pdf',\n 'text/plain': 'txt',\n 'text/html': 'html',\n 'application/json': 'json',\n 'application/octet-stream': 'bin'\n}\nconst extMap = Object.fromEntries(Object.entries(mimeMap).map(([k, v]) => [v, k]))\nconst mime = {\n extension: (contentType) => mimeMap[contentType] || false,\n lookup: (filename) => {\n const ext = filename.split('.').pop().toLowerCase()\n return extMap[ext] || false\n }\n}\n\nconst ns = UI.ns\nconst utils = UI.utils\nconst kb = store\n\n/* Mugshot Gallery\n*\n* A widget for managing a set of images.\n* Make this a form field?\n*/\nexport function renderMugshotGallery (dom, subject) {\n function localComplain (message) {\n galleryDiv.appendChild(UI.widgets.errorMessageBlock(dom, message, 'pink'))\n }\n\n async function linkToPicture (subject, pic, remove) {\n const link = [\n $rdf.st(subject, ns.vcard('hasPhoto'), pic, subject.doc())\n ]\n try {\n if (remove) {\n await kb.updater.update(link, [])\n } else {\n await kb.updater.update([], link)\n }\n } catch (err) {\n const msg = 'Writing back image link FAILED ' + pic + '. Stack: ' + err\n debug.error(msg)\n throw new Error('Writing back image link FAILED')\n }\n }\n\n function handleDroppedThing (thing) {\n kb.fetcher.nowOrWhenFetched(thing.doc(), function (ok, mess) {\n if (!ok) {\n debug.error('Error looking up dropped thing ' + thing + '. Stack: ' + mess)\n } else {\n const types = kb.findTypeURIs(thing)\n for (const ty in types) {\n debug.log('drop object type includes: ' + ty) // @@ Allow email addresses and phone numbers to be dropped?\n }\n debug.log('Default: assume web page ' + thing) // icon was: UI.icons.iconBase + 'noun_25830.svg'\n kb.add(subject, ns.wf('attachment'), thing, subject.doc())\n // @@ refresh UI\n }\n })\n }\n\n function uploadFileToContact (filename, contentType, data) {\n // const fileExtension = filename.split('.').pop() // .toLowerCase()\n const extension = mime.extension(contentType)\n if (contentType !== mime.lookup(filename)) {\n filename += '_.' + extension\n debug.warn('MIME TYPE MISMATCH -- adding extension: ' + filename)\n }\n let prefix, predicate\n const isImage = contentType.startsWith('image')\n if (isImage) {\n prefix = 'image_'\n predicate = ns.vcard('hasPhoto')\n } else {\n prefix = 'attachment_'\n predicate = ns.wf('attachment')\n }\n\n let n, pic\n for (n = 0; ; n++) {\n // Check filename is not used or invent new one\n pic = kb.sym(subject.dir().uri + filename)\n if (!kb.holds(subject, ns.vcard('hasPhoto'), pic)) {\n break\n }\n filename = prefix + n + '.' + extension\n }\n debug.log(\n 'Putting ' +\n data.byteLength +\n ' bytes of ' +\n contentType +\n ' to ' +\n pic\n )\n kb.fetcher\n .webOperation('PUT', pic.uri, {\n data,\n contentType\n })\n .then(function (response) {\n if (!response.ok) {\n debug.error('Upload of ' + pic + ' failed: ' + response.status + ' ' + response.statusText)\n localComplain('Error uploading picture. If the problem persists, contact admin.')\n return\n }\n debug.log('Upload picture put OK: ' + pic)\n kb.add(subject, predicate, pic, subject.doc())\n kb.fetcher\n .putBack(subject.doc(), { contentType: 'text/turtle' })\n .then(\n function (_response) {\n if (isImage) {\n mugshotDiv.refresh()\n }\n },\n function (err) {\n debug.error(' Write back image link FAIL ' + pic + '. Stack: ' + err)\n }\n )\n })\n }\n\n // When a set of URIs are dropped on\n async function handleURIsDroppedOnMugshot (uris) {\n for (const u of uris) {\n let thing = $rdf.sym(u) // Attachment needs text label to disinguish I think not icon.\n debug.log('Dropped on mugshot thing ' + thing) // icon was: UI.icons.iconBase + 'noun_25830.svg'\n if (u.startsWith('http') && u.indexOf('#') < 0) {\n // Plain document\n // Take a copy of a photo on the web:\n if (u.startsWith('http:')) { // because of browser mixed content stuff can't read http:\n thing = $rdf.sym('https:' + u.slice(5))\n }\n const options = { withCredentials: false, credentials: 'omit' }\n let result\n try {\n result = await kb.fetcher.webOperation('GET', thing.uri, options)\n } catch (err) {\n debug.error('Fetch error trying to GET picture ' + thing + '. Stack: ' + err)\n handleDroppedThing(thing)\n return\n }\n const contentType = result.headers.get('Content-Type')\n let pathEnd = thing.uri.split('/').slice(-1)[0] // last segment as putative filename\n pathEnd = pathEnd.split('?')[0] // chop off any query params\n const data = await result.arrayBuffer()\n if (!result.ok) {\n debug.error('Cant download, so will link image. ' + thing + ':' + result.status)\n handleDroppedThing(thing)\n return\n }\n uploadFileToContact(pathEnd, contentType, data)\n return\n } else {\n localComplain('Not a web document URI, cannot copy ' + thing + ' as picture.')\n }\n handleDroppedThing(thing)\n }\n }\n\n // Drop an image file to set up the mugshot\n function droppedFileHandler (files) {\n for (let i = 0; i < files.length; i++) {\n const f = files[i]\n debug.log(\n ' contacts: Filename: ' +\n f.name +\n ', type: ' +\n (f.type || 'n/a') +\n ' size: ' +\n f.size +\n ' bytes, last modified: ' +\n (f.lastModifiedDate\n ? f.lastModifiedDate.toLocaleDateString()\n : 'n/a')\n ) // See e.g. https://www.html5rocks.com/en/tutorials/file/dndfiles/\n\n // @@ Add: progress bar(s)\n const reader = new FileReader()\n reader.onload = (function (theFile) {\n return function (e) {\n const data = e.target.result\n debug.log(' File read byteLength : ' + data.byteLength)\n const filename = encodeURIComponent(theFile.name)\n const contentType = theFile.type\n uploadFileToContact(filename, contentType, data)\n }\n })(f)\n reader.readAsArrayBuffer(f)\n }\n }\n\n function elementForImage (image) {\n const img = dom.createElement('img')\n img.classList.add('mugshotImage')\n img.setAttribute('alt', image ? 'Contact photo' : 'Drop photo here')\n UI.widgets.makeDropTarget(\n img,\n handleURIsDroppedOnMugshot,\n droppedFileHandler\n )\n if (image) {\n // img.setAttribute('src', image.uri) use token and works with NSS but not with CSS\n // we need to get image with authenticated fetch\n store.fetcher._fetch(image.uri)\n .then(function (response) {\n return response.blob()\n })\n .then(function (myBlob) {\n const objectURL = URL.createObjectURL(myBlob)\n img.setAttribute('src', objectURL)\n })\n UI.widgets.makeDraggable(img, image)\n }\n return img\n }\n\n function syncMugshots () {\n let images = kb.each(subject, ns.vcard('hasPhoto')) // Priviledge vcard ones\n images.sort() // arbitrary consistency\n images = images.slice(0, 5) // max number for the space\n if (images.length === 0) {\n mugshotDiv.innerHTML = '' // strictly, don't remove it if already there\n if (editable) {\n mugshotDiv.appendChild(placeholder) // A head image to drop pictures on\n } // otherwise leave gallery empty .. nothing to see here folks\n } else {\n utils.syncTableToArray(mugshotDiv, images, elementForImage)\n }\n }\n\n // Good URI for a Camera picture\n function getImageDoc () {\n const imageDoc = kb.sym(\n subject.dir().uri + 'Image_' + Date.now() + '.png'\n )\n return imageDoc\n }\n // Store picture\n async function tookPicture (imageDoc) {\n if (imageDoc) {\n await linkToPicture(subject, imageDoc)\n syncMugshots()\n }\n }\n\n function trashCan () {\n const button = UI.widgets.button(\n dom,\n UI.icons.iconBase + 'noun_925021.svg',\n 'Drag here to delete',\n undefined,\n { 'aria-label': 'Delete picture - drag picture here' }\n )\n async function droppedURIHandler (uris) {\n const images = kb\n .each(subject, ns.vcard('hasPhoto'))\n .map(x => x.uri)\n for (const uri of uris) {\n if (!images.includes(uri)) {\n alertDialog('Only drop pictures onto this trash can.')\n return\n }\n if (await confirmDialog('Really DELETE picture?')) {\n try {\n debug.log('Unlinking image file ' + uri)\n await linkToPicture(subject, kb.sym(uri), true)\n debug.log('Deleting image file ' + uri)\n await kb.fetcher.webOperation('DELETE', uri)\n } catch (err) {\n const msg = 'Error deleting picture. If it persists, contact your admin.'\n localComplain(msg)\n return\n }\n }\n }\n syncMugshots()\n }\n UI.widgets.makeDropTarget(button, droppedURIHandler, null)\n return button\n }\n\n function renderImageTools () {\n const imageToolTable = dom.createElement('table')\n const row = imageToolTable.appendChild(dom.createElement('tr'))\n const left = row.appendChild(dom.createElement('td'))\n const middle = row.appendChild(dom.createElement('td'))\n const right = row.appendChild(dom.createElement('td'))\n\n left.appendChild(\n UI.media.cameraButton(dom, kb, getImageDoc, tookPicture)\n )\n try {\n middle.appendChild(\n UI.widgets.fileUploadButtonDiv(dom, droppedFileHandler)\n )\n } catch (e) {\n debug.log('ignore fileUploadButtonDiv error for now', e)\n }\n right.appendChild(trashCan())\n return imageToolTable\n }\n\n // Body of renderMugshotGallery\n\n const editable = kb.updater.editable(subject.doc().uri, kb)\n const galleryDiv = dom.createElement('div')\n const mugshotDiv = galleryDiv.appendChild(dom.createElement('div'))\n const placeholder = elementForImage()\n UI.widgets.setImage(placeholder, subject) // Fallback icon or get from web\n syncMugshots()\n mugshotDiv.refresh = syncMugshots\n if (editable) {\n galleryDiv.appendChild(renderImageTools())\n }\n return galleryDiv\n}\n","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./groupMembership.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./groupMembership.css\";\n export default content && content.locals ? content.locals : undefined;\n","import { addPersonToGroup, groupMembers, getDataModelIssues } from './contactLogic'\nimport * as UI from 'solid-ui'\nimport { authn, store } from 'solid-logic'\nimport * as debug from './debug'\nimport { complain, alertDialog, getSameAs, deleteRecursive, deleteThingAndDoc, compareForSort, nameFor } from './localUtils'\nimport { groupMembership } from './groupMembershipControl'\n\nconst ns = UI.ns\nconst utils = UI.utils\nconst kb = store\nlet dom\nlet selectedGroups = {}\nlet selectedPeople = {}\nlet ulPeople = null\nlet ulGroups = null\nlet searchInput = null\nlet cardMain = null\nlet book = null\nlet dataBrowserContext = null\nlet onGroupButtonClick = null\n\n// ######## Group presenter\n\nexport function setActiveGroupButton (groupsUl, activeBtn) {\n groupsUl.querySelectorAll('button').forEach(btn => {\n btn.classList.remove('btn-primary', 'allGroupsButton--selected', 'allGroupsButton--active', 'allGroupsButton--loaded')\n btn.classList.add('btn-secondary')\n })\n if (activeBtn) {\n activeBtn.classList.remove('btn-secondary')\n activeBtn.classList.add('btn-primary')\n }\n}\n\nexport function renderGroupButtons (currentBook, groupsUl, options, domElement, groupsSelected, peopleUl, searchEl, cardMainEl, context, groupClickCallback) {\n dom = domElement\n selectedGroups = groupsSelected || {}\n if (peopleUl) ulPeople = peopleUl\n if (searchEl) searchInput = searchEl\n if (cardMainEl) cardMain = cardMainEl\n if (context) dataBrowserContext = context\n if (groupClickCallback) onGroupButtonClick = groupClickCallback\n book = currentBook\n ulGroups = groupsUl\n const groups = groupsInOrder(book, options)\n utils.syncTableToArrayReOrdered(ulGroups, groups, renderGroupLi)\n}\n\n/** Create the common DOM structure for a group list item (li + button).\n * Returns { groupLi, groupButton, name } so callers can attach their own handlers.\n */\nexport function createGroupLi (group) {\n const name = kb.any(group, ns.vcard('fn'))\n const groupLi = dom.createElement('li')\n groupLi.setAttribute('role', 'listitem')\n groupLi.setAttribute('aria-label', name ? name.value : 'Some group')\n groupLi.subject = group\n UI.widgets.makeDraggable(groupLi, group)\n\n const groupButton = groupLi.appendChild(dom.createElement('button'))\n groupButton.setAttribute('type', 'button')\n groupButton.innerHTML = name ? name.value : 'Some group'\n groupButton.classList.add('allGroupsButton', 'actionButton', 'btn-secondary', 'action-button-focus')\n\n return { groupLi, groupButton, name }\n}\n\nexport async function handleURIsDroppedOnGroup (uris, group) {\n for (const u of uris) {\n let thing = kb.sym(u)\n try {\n thing = await addPersonToGroup(thing, group)\n } catch (_e) {\n const msg = 'Error adding to group. Make sure you are adding a contact URI.'\n alertDialog(msg)\n }\n if (thing) refreshNames(ulPeople)\n }\n}\n\nfunction renderGroupLi (group) {\n function groupLiClickListener (event) {\n event.preventDefault()\n setActiveGroupButton(ulGroups, groupButton)\n if (onGroupButtonClick) onGroupButtonClick()\n if (!event.metaKey) {\n for (const key in selectedGroups) delete selectedGroups[key] // If Command key pressed, accumulate multiple\n }\n selectedGroups[group.uri] = !selectedGroups[group.uri]\n refreshThingsSelected(ulGroups, selectedGroups)\n // Load group members and refresh people list\n kb.fetcher.nowOrWhenFetched(group.doc(), undefined, function (ok, message) {\n if (!ok) {\n debug.error('Cannot load one group: ' + group + '. Stack: ' + message)\n }\n refreshNames(ulPeople, null, false)\n })\n }\n\n const { groupLi, groupButton } = createGroupLi(group)\n\n groupButton.addEventListener('click', groupLiClickListener, false)\n UI.widgets.makeDropTarget(groupLi, uris => handleURIsDroppedOnGroup(uris, group))\n groupLi.addEventListener('click', groupLiClickListener, true)\n return groupLi\n} // renderGroupLi\n\nexport function selectAllGroups (\n selectedGroups,\n ulGroups,\n callbackFunction\n) {\n function fetchGroupAndSelect (group, groupLi) {\n return new Promise((resolve, reject) => {\n groupLi.classList.add('group-loading')\n groupLi.setAttribute('aria-busy', 'true')\n kb.fetcher.nowOrWhenFetched(group.doc(), undefined, function (\n ok,\n message\n ) {\n if (!ok) {\n const msg = 'Cannot load group ' + group + '. Stack: ' + message\n debug.error(msg)\n if (callbackFunction) callbackFunction(false, msg)\n reject(msg)\n return\n }\n groupLi.classList.remove('group-loading')\n groupLi.setAttribute('aria-busy', 'false')\n groupLi.classList.add('selected')\n selectedGroups[group.uri] = true\n refreshThingsSelected(ulGroups, selectedGroups)\n refreshNames(ulPeople, null) // @@ every time??\n if (callbackFunction) callbackFunction(true)\n resolve(true)\n })\n })\n }\n\n for (let k = 0; k < ulGroups.children.length; k++) {\n const groupLi = ulGroups.children[k]\n const group = groupLi.subject\n if (!group) continue // Skip non-group items (e.g. All contacts, New group)\n fetchGroupAndSelect(group, groupLi)\n .catch(err => {\n if (callbackFunction) callbackFunction(false, err)\n })\n } // for each row\n}\n\nexport function refreshThingsSelected (ul, selectionArray) {\n for (let i = 0; i < ul.children.length; i++) {\n const li = ul.children[i]\n if (li.subject) {\n li.classList.toggle('selected', !!selectionArray[li.subject.uri])\n }\n }\n}\n\nexport function syncGroupUl (book, options, groupsUl, domElement, groupsSelected, peopleUl, searchEl) {\n dom = domElement\n if (groupsSelected) selectedGroups = groupsSelected\n if (peopleUl) ulPeople = peopleUl\n if (searchEl) searchInput = searchEl\n ulGroups = groupsUl\n const groups = groupsInOrder(book, options)\n if (groups.length > 0) {\n renderGroupLi(groups[0]) // pre-render one to get the style right, then throw it away\n }\n utils.syncTableToArrayReOrdered(groupsUl, groups, renderGroupLi)\n // refreshThingsSelected(groupsUl, selectedGroups)\n}\n\nfunction groupsInOrder (book, options) {\n let sortMe = []\n if (options.foreignGroup) {\n sortMe.push([\n '',\n kb.any(options.foreignGroup, ns.vcard('fn')),\n options.foreignGroup\n ])\n }\n if (book) {\n const groupIndex = kb.any(book, ns.vcard('groupIndex'))\n const gs = book ? kb.each(book, ns.vcard('includesGroup'), null, groupIndex) : []\n const gs2 = gs.map(function (g) {\n return [book, kb.any(g, ns.vcard('fn')), g]\n })\n sortMe = sortMe.concat(gs2)\n sortMe.sort()\n }\n return sortMe.map(tuple => tuple[2])\n}\n\nexport async function loadAllGroups (book) {\n const groupIndex = kb.any(book, ns.vcard('groupIndex'))\n if (groupIndex) {\n await kb.fetcher.load(groupIndex)\n const gs = book ? kb.each(book, ns.vcard('includesGroup'), null, groupIndex) : []\n await kb.fetcher.load(gs)\n return gs\n } else {\n return [] // no groups\n }\n}\n\n// The book could be the main subject, or linked from a group we are dealing with\nexport function findBookFromGroups (book) {\n if (book) {\n return book\n }\n let g\n for (const gu in selectedGroups) {\n g = kb.sym(gu)\n const b = kb.any(undefined, ns.vcard('includesGroup'), g)\n if (b) return b\n }\n throw new Error(\n 'findBookFromGroups: Cant find address book which this group is part of'\n )\n}\n// ######## Group presenter - END\n\n// ######## Person presenter\n/** Refresh the list of names */\nexport function refreshNames (ulPeopleArg, detailsView, autoSelect = true) {\n // If the caller did not explicitly pass a list element, fall back to the\n // global variable that other helpers (renderGroupButtons, syncGroupUl, etc.)\n // keep up to date. This allows callers that don't have easy access to the\n // element to simply invoke `refreshNames()` and get the behaviour they\n // expect when the address-book UI is present.\n const ul = ulPeopleArg || ulPeople\n\n // Guard: ul must be a DOM element with children. Callers sometimes pass the\n // wrong thing (e.g. a person object) which leads to the\n // \"Cannot read properties of undefined (reading 'length')\" error in\n // syncTableToArrayReOrdered. Bail out early if the value is not valid.\n if (!ul || !ul.children || typeof ul.children.length !== 'number') {\n debug.warn('refreshNames called with invalid ulPeople:', ul)\n return\n }\n\n function setPersonListener (personLi, person) {\n function handleSelect (event) {\n event.preventDefault()\n selectPerson(ul, person, cardMain)\n }\n personLi.addEventListener('click', handleSelect)\n personLi.addEventListener('keydown', function (event) {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n handleSelect(event)\n }\n })\n }\n\n let cards = []\n const groups = Object.keys(selectedGroups).map(groupURI => kb.sym(groupURI))\n groups.forEach(group => {\n if (selectedGroups[group.value]) {\n cards = cards.concat(groupMembers(kb, group))\n }\n })\n cards.sort(compareForSort) // @@ sort by name not UID later\n for (let k = 0; k < cards.length - 1;) {\n if (cards[k].uri === cards[k + 1].uri) {\n cards.splice(k, 1) // Eliminate duplicates from more than one group\n } else {\n k++\n }\n }\n\n function renderNameInGroupList (person, ul) {\n const personLi = dom.createElement('li')\n personLi.setAttribute('role', 'listitem')\n personLi.setAttribute('tabindex', '0')\n personLi.classList.add('personLi')\n personLi.subject = person\n UI.widgets.makeDraggable(personLi, person)\n\n // Container for the row\n const rowDiv = dom.createElement('div')\n rowDiv.classList.add('personLi-row')\n\n // Left: Avatar\n const avatarDiv = dom.createElement('div')\n avatarDiv.classList.add('personLi-avatar')\n // Placeholder avatar (shown initially while person doc loads)\n const placeholderEl = dom.createElement('div')\n placeholderEl.classList.add('avatar-placeholder')\n placeholderEl.innerHTML = '<svg aria-hidden=\"true\" width=\"36\" height=\"36\" viewBox=\"0 0 36 36\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"18\" cy=\"18\" r=\"18\" fill=\"#e0e0e0\"/><text x=\"50%\" y=\"58%\" text-anchor=\"middle\" fill=\"#595959\" font-size=\"16\" font-family=\"Arial\" dy=\".3em\">?</text></svg>'\n avatarDiv.appendChild(placeholderEl)\n\n // Get name early so it can be used in trySetAvatar\n const name = nameFor(person) || 'Unknown Name'\n\n // Try to set avatar from already-loaded data, or fetch the person's doc\n function trySetAvatar () {\n const avatarUrl = kb.any(person, ns.vcard('hasPhoto'))\n if (avatarUrl && avatarUrl.value) {\n const img = dom.createElement('img')\n img.src = avatarUrl.value\n img.alt = name + ' avatar'\n avatarDiv.replaceChild(img, avatarDiv.firstChild)\n }\n }\n trySetAvatar() // check if already in store\n\n // Load person's own document in background to get hasPhoto\n kb.fetcher.nowOrWhenFetched(person.doc(), undefined, function (ok, message) {\n if (!ok) {\n debug.error('Cannot load contact: ' + person + '. Stack: ' + message)\n personLi.classList.add('personLi--error')\n return // skip avatar – doc is unavailable\n }\n trySetAvatar()\n })\n\n // Center: Name\n const infoDiv = dom.createElement('div')\n infoDiv.classList.add('personLi-info')\n\n personLi.setAttribute('aria-label', name)\n const nameDiv = dom.createElement('div')\n nameDiv.classList.add('personLi-name')\n nameDiv.textContent = name\n\n infoDiv.appendChild(nameDiv)\n\n // Right: Arrow icon\n const arrowDiv = dom.createElement('div')\n arrowDiv.classList.add('personLi-arrow')\n arrowDiv.innerHTML = '<svg aria-hidden=\"true\" width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M6 4.5L11.25 9L6 13.5\" stroke=\"#595959\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'\n\n // Assemble\n rowDiv.appendChild(avatarDiv)\n rowDiv.appendChild(infoDiv)\n rowDiv.appendChild(arrowDiv)\n personLi.appendChild(rowDiv)\n\n setPersonListener(personLi, person)\n return personLi\n }\n\n utils.syncTableToArrayReOrdered(ul, cards, person => renderNameInGroupList(person, ul))\n refreshFilteredPeople(ul, autoSelect, detailsView || cardMain)\n} // refreshNames\n\nexport function selectPerson (ulPeople, person, detailsView) {\n if (!detailsView) return\n if (detailsView.parentNode) detailsView.parentNode.classList.remove('hidden')\n detailsView.innerHTML = 'Loading...'\n detailsView.setAttribute('aria-busy', 'true')\n detailsView.classList.add('detailsSectionContent--wide')\n selectedPeople = {}\n selectedPeople[person.uri] = true\n refreshFilteredPeople(ulPeople, false, detailsView) // Color to remember which one you picked\n let local\n try {\n local = book ? localNode(person) : person\n } catch (err) {\n detailsView.innerHTML = ''\n detailsView.setAttribute('aria-busy', 'false')\n complain(detailsView, dom, 'Cannot load contact: ' + err.message)\n return\n }\n kb.fetcher.nowOrWhenFetched(local.doc(), undefined, function (\n ok,\n message\n ) {\n detailsView.innerHTML = ''\n detailsView.setAttribute('aria-busy', 'false')\n if (!ok) {\n debug.error('Failed to load contact card: ' + local + '. Stack: ' + message)\n complain(detailsView, dom, 'Failed to load contact. If it persists, contact your admin.')\n return\n }\n // debug.log(\"Loaded card \" + local + '\\n')\n\n // Top-right toolbar with link icon and delete button\n const toolbar = dom.createElement('div')\n toolbar.classList.add('contact-toolbar')\n const linkEl = UI.widgets.linkIcon(dom, local)\n linkEl.setAttribute('title', 'Uri of contact')\n toolbar.appendChild(linkEl)\n\n if (authn.currentUser()) {\n // Add in a delete button to delete from AB\n const deleteButton = UI.widgets.deleteButtonWithCheck(\n dom,\n toolbar, // appends it to toolbar.appendChild(deleteButton)\n 'contact',\n async function () {\n const container = person.dir() // ASSUMPTION THAT CARD IS IN ITS OWN DIRECTORY\n\n const pname = kb.any(person, ns.vcard('fn'))\n debug.log('We are about to delete the contact ' + pname)\n await loadAllGroups() // need to wait for all groups to be loaded in case they have a link to this person\n // load people.ttl\n const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))\n await kb.fetcher.load(nameEmailIndex)\n\n // - delete person's WebID's in each Group\n // - delete the references to it in group files and save them back\n // - delete the reference in people.ttl and save it back\n\n // find all Groups\n const groups = groupMembership(person)\n let removeFromGroups = []\n // find person WebID's\n groups.forEach(group => {\n const webids = getSameAs(kb, person, group.doc())\n // for each check in each Group that it is not used by an other person then delete\n webids.forEach(webid => {\n if (getSameAs(kb, webid, group.doc()).length === 1) {\n removeFromGroups = removeFromGroups.concat(kb.statementsMatching(group, ns.vcard('hasMember'), webid, group.doc()))\n }\n })\n })\n\n // Only if folder deletion succeeds, proceed with person deletion\n await kb.updater.updateMany(removeFromGroups)\n\n try {\n await deleteThingAndDoc(person)\n } catch (err) {\n complain(detailsView, dom, 'Failed to delete contact. If it persists, contact your admin.')\n return\n }\n\n try {\n await deleteRecursive(kb, container, toolbar, dom)\n } catch (err) {\n const msg = 'Failed to delete contact. If it persists, contact your admin.'\n complain(detailsView, dom, msg)\n return\n }\n refreshNames(ulPeople, detailsView)\n detailsView.innerHTML = 'Contact data deleted.'\n }\n )\n deleteButton.classList.add('deleteButton')\n }\n detailsView.appendChild(toolbar)\n\n detailsView.classList.add('detailsSectionContent--wide')\n detailsView.appendChild(renderPane(local, 'contact'))\n })\n}\n\nexport function deselectAllPeople (ulPeople) {\n selectedPeople = {}\n if (ulPeople) {\n for (let i = 0; i < ulPeople.children.length; i++) {\n ulPeople.children[i].classList.remove('selected')\n }\n }\n}\n\nexport function refreshFilteredPeople (ulPeople, active, detailsView) {\n let count = 0\n let lastRow = null\n for (let i = 0; i < ulPeople.children.length; i++) {\n const liElement = ulPeople.children[i]\n const matches = filterName(nameFor(liElement.subject))\n if (matches) {\n count++\n lastRow = liElement\n }\n liElement.classList.toggle('selected', matches && !!selectedPeople[liElement.subject.uri])\n liElement.classList.toggle('hidden', !matches)\n }\n if (count === 1 && active) {\n const unique = lastRow.subject\n selectPerson(ulPeople, unique, detailsView)\n }\n}\n\nfunction filterName (name) {\n const filter = searchInput.value.trim().toLowerCase()\n if (filter.length === 0) return true\n const parts = filter.split(' ') // Each name part must be somewhere\n for (let j = 0; j < parts.length; j++) {\n const word = parts[j]\n if (name.toLowerCase().indexOf(word) < 0) return false\n }\n return true\n}\n\nfunction renderPane (subject, paneName) {\n const p = dataBrowserContext.session.paneRegistry.byName(paneName)\n const d = p.render(subject, dataBrowserContext)\n d.classList.add('renderPane')\n return d\n}\n\nfunction localNode (person) {\n const aliases = kb.allAliases(person)\n const prefix = book.dir().uri\n for (let i = 0; i < aliases.length; i++) {\n if (aliases[i].uri.slice(0, prefix.length) === prefix) {\n return aliases[i]\n }\n }\n throw new Error('No local URI for ' + person)\n}\n\n// Check every group is in the list and add it if not.\nexport async function checkDataModel (book, detailsSectionContent) {\n // await kb.fetcher.load(groups) // asssume loaded already\n const groups = await loadAllGroups(book)\n\n if (groups && groups.length > 0) {\n const { del, ins } = await getDataModelIssues(groups)\n\n if (authn.currentUser()) {\n if (del.length) {\n UI.widgets.deleteButtonWithCheck(\n dom,\n detailsSectionContent, // where it appends it to\n 'contact',\n async function () {\n await kb.updater.updateMany(del, ins)\n debug.log('Deleted ' + del.length + ' bad statements from groups')\n })\n }\n }\n }\n}\n\n// Prepare book data once so askName forms load instantly\nexport async function ensureBookLoaded () {\n const ourBook = findBookFromGroups(book)\n try {\n await kb.fetcher.load(ourBook)\n } catch (err) {\n throw new Error('Book won\\'t load:' + ourBook)\n }\n const nameEmailIndex = kb.any(ourBook, ns.vcard('nameEmailIndex'))\n if (!nameEmailIndex) throw new Error('No nameEmailIndex')\n await kb.fetcher.load(nameEmailIndex)\n}\n","// Render a control to record the group memberships we have for this agent\nimport * as UI from 'solid-ui'\nimport { store, authn } from 'solid-logic'\nimport './styles/groupMembership.css'\nimport * as debug from './debug'\nimport { normalizeGroupUri, confirmDialog, alertDialog } from './localUtils'\nimport { refreshNames } from './addressBookPresenter'\nimport { vcardWebIDs } from './webidControl'\n\nconst ns = UI.ns\nconst kb = store\n\n// Groups the person is a member of\nexport function groupMembership (person, store = kb) {\n let groups = store.statementsMatching(null, ns.owl('sameAs'), person).map(st => st.why)\n .concat(store.each(null, ns.vcard('hasMember'), person))\n const strings = new Set(groups.map(group => normalizeGroupUri(group.uri))) // remove dups with normalized URIs\n groups = [...strings].map(uri => store.sym(uri))\n return groups\n}\n\n/**\n * Render the group membership section for a given person.\n *\n * @param person - the contact whose memberships are being edited\n * @param context - the Data Browser context used by the pane registry\n * @param ulPeople - **optional** the `<ul>` element containing the master\n * people list. When provided (e.g. by the contacts pane) the control will\n * automatically call `refreshNames(ulPeople)` after removing a membership so\n * that the list on the left reflects the change. If `null` this behaviour\n * is skipped.\n */\nexport async function renderGroupMemberships (person, context, ulPeople) {\n // keep a reference to the people list (if any) so callers can ask us to\n // refresh it when group membership changes. The callers that render an\n // address-book view pass their `ulPeople` element; other consumers may not\n // have one and can simply ignore it.\n const peopleUl = ulPeople || null\n\n // Remove a person from a group\n async function removeFromGroup (person, group) {\n const pname = kb.any(person, ns.vcard('fn'))\n const gname = kb.any(group, ns.vcard('fn'))\n // find all WebIDs of thing\n const thingwebids = kb.each(null, ns.owl('sameAs'), person, group.doc())\n // WebID can be deleted only if not used in another thing\n let webids = []\n thingwebids.forEach(webid => {\n if (kb.statementsMatching(webid, ns.owl('sameAs'), person, group.doc())) webids = webids.concat(webid)\n })\n webids = vcardWebIDs(kb, person).map(webid => webid.value)\n // When checking how many groups this entity belongs to we should look\n // at the person **and** any of their webID nodes. Build an array of\n // named nodes so we can query all of them.\n const webidNodes = webids.map(u => kb.sym(u))\n const members = [person].concat(webidNodes)\n // collect all groups for any of these members, dedupe by URI\n let groups = members\n .flatMap(m => kb.each(null, ns.vcard('hasMember'), m))\n groups = [...new Set(groups.map(g => g.uri))].map(u => kb.sym(u))\n if (groups.length < 2) {\n alertDialog(\n 'Must be a member of at least one group. Add to another group first.'\n )\n return\n }\n const message = 'Remove ' + pname + ' from group ' + gname + '?'\n if (await confirmDialog(message)) {\n let del = kb\n .statementsMatching(person, undefined, undefined, group.doc())\n .concat(kb.statementsMatching(undefined, undefined, person, group.doc()))\n webids.forEach(webid => {\n if (kb.statementsMatching(webid, ns.owl('sameAs'), undefined, group.doc()).length < 2) {\n del = del.concat(kb.statementsMatching(undefined, undefined, webid, group.doc()))\n }\n })\n try {\n await kb.updater.update(del, [])\n } catch (err) {\n const message = 'Error removing member from group ' + group + ': ' + err\n container.appendChild(UI.widgets.errorMessageBlock(dom, message, 'pink'))\n return\n }\n debug.log('Removed ' + pname + ' from group ' + gname)\n // to allow refresh of card groupList\n kb.fetcher.unload(group.doc())\n await kb.fetcher.load(group.doc())\n syncGroupPills()\n // also update the people list if one exists (or via global fallback)\n refreshNames(peopleUl)\n }\n }\n\n function createGroupItem (group) {\n const gname = kb.any(group, ns.vcard('fn'))\n const label = gname ? gname.value : group.uri\n\n const li = dom.createElement('li')\n li.classList.add('group-membership-item')\n\n // Main group button\n const btn = dom.createElement('button')\n btn.setAttribute('type', 'button')\n btn.classList.add('allGroupsButton', 'actionButton', 'btn-secondary', 'action-button-focus')\n btn.textContent = label\n btn.title = label\n li.appendChild(btn)\n\n // Toolbar below the button: link icon + delete button\n const toolbar = dom.createElement('div')\n toolbar.classList.add('group-membership-toolbar')\n\n // Link icon\n const linkEl = UI.widgets.linkIcon(dom, group)\n linkEl.setAttribute('title', 'Link to ' + label)\n toolbar.appendChild(linkEl)\n\n if (authn.currentUser()) {\n // Delete button\n UI.widgets.deleteButtonWithCheck(\n dom,\n toolbar,\n 'membership in ' + label,\n async function () {\n // async operation handles its own refresh once the group doc has\n // been reloaded\n await removeFromGroup(person, group)\n }\n )\n }\n\n li.appendChild(toolbar)\n return li\n }\n\n function syncGroupPills (groups = null) {\n // Clear previous render so we don't keep appending duplicate headers / lists\n container.innerHTML = ''\n\n const header = dom.createElement('h3')\n header.classList.add('group-membership-header')\n header.textContent = 'Part of groups'\n container.appendChild(header)\n\n const pillsWrapper = dom.createElement('ul')\n pillsWrapper.classList.add('group-pills-wrapper')\n container.appendChild(pillsWrapper)\n\n groups = groups || groupMembership(person, kb)\n\n if (groups.length === 0) {\n pillsWrapper.innerHTML = '<span>Not part of any Address Book group.</span>'\n } else {\n pillsWrapper.innerHTML = ''\n }\n\n groups.forEach(group => {\n pillsWrapper.appendChild(createGroupItem(group))\n })\n }\n\n async function loadGroupsFromBook (book = null) {\n if (!book) {\n book = kb.any(undefined, ns.vcard('includesGroup'))\n if (!book) {\n return [] // no book => no groups\n }\n }\n const groupIndex = kb.any(book, ns.vcard('groupIndex'))\n const gs = book ? kb.each(book, ns.vcard('includesGroup'), null, groupIndex) : []\n await kb.fetcher.load(gs)\n return gs\n }\n\n const { dom } = context\n const kb = context.session.store\n\n const container = dom.createElement('div')\n container.classList.add('group-membership-container')\n\n // find book any group and load all groups (so membership checks have the data they need)\n await loadGroupsFromBook()\n\n // renders the Part of Group\n container.refresh = syncGroupPills\n syncGroupPills()\n return container\n}\n","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./individual.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./individual.css\";\n export default content && content.locals ? content.locals : undefined;\n","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./contactsRDFFormsEnforced.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./contactsRDFFormsEnforced.css\";\n export default content && content.locals ? content.locals : undefined;\n","import { sym, Namespace, parse } from 'rdflib'\nimport { widgets } from 'solid-ui'\n\nconst baseUri = 'https://solidos.github.io/contacts-pane/src/ontology/'\n\nexport function renderForm (\n div,\n subject, // Represents the RDF that fills the form\n formSource, // The imported form Turtle source\n formName, // The name of the form file (e.g., 'socialMedia.ttl')\n store,\n dom,\n editableProfile,\n whichForm) {\n // --- Form resource setup ---\n const formUri = baseUri + formName // Full URI to the form file\n const exactForm = whichForm || 'this' // If there are more 'a ui:Form' elements in a form file\n const formThis = Namespace(formUri + '#')(exactForm) // NamedNode for #this in the form\n\n loadDocument(store, formSource, formName, formUri)\n\n widgets.appendForm(\n dom,\n div,\n {},\n subject,\n formThis,\n editableProfile,\n (ok, mes) => {\n if (!ok) widgets.errorMessageBlock(dom, mes)\n }\n )\n} // renderForm\n\n// we need to load into the store some additional information about Social Media accounts\nexport function loadDocument (\n store,\n documentSource,\n documentName,\n documentURI\n) {\n const finalDocumentUri = documentURI || baseUri + documentName // Full URI to the file\n const document = sym(finalDocumentUri) // rdflib NamedNode for the document\n\n if (!store.holds(undefined, undefined, undefined, document)) {\n // we are using the social media form because it contains the information we need\n // the form can be used for both use cases: create UI for edit and render UI for display\n parse(documentSource, store, finalDocumentUri, 'text/turtle', () => null) // Load doc directly\n }\n}\n","import * as UI from 'solid-ui'\nimport { authn, store } from 'solid-logic'\nimport { renderMugshotGallery } from './mugshotGallery'\nimport { renderWebIdControl, renderPublicIdControl } from './webidControl'\nimport { renderGroupMemberships } from './groupMembershipControl'\nimport formsSource from './ontology/individualAndOrganizationForm.ttl'\nimport VCARD_ONTOLOGY_TEXT from './ontology/vcard.ttl'\nimport './styles/individual.css'\nimport './styles/contactsRDFFormsEnforced.css'\nimport { renderForm, loadDocument } from './rdfFormsHelper'\nimport * as debug from './debug'\nimport { skipLabelsFromTabbing, isAWebID } from './localUtils'\n\nconst ns = UI.ns\nconst kb = store\n\nconst formsName = 'individualAndOrganizationForm.ttl' // The name of the form file\nconst vcardName = 'vcard.ttl' // The name of the vcard file\n\nexport async function renderIndividual (dom, div, subject, dataBrowserContext) {\n const t = kb.findTypeURIs(subject)\n const isOrganization = !!(t[ns.vcard('Organization').uri] || t[ns.schema('Organization').uri])\n const editable = kb.updater.editable(subject.doc().uri, kb)\n\n // We load the local form document\n loadDocument(kb, formsSource, formsName)\n\n // We need to make sure VCARD ontology is loaded in the store\n const vcardOntUri = UI.ns.vcard('Type').doc().uri // URI to VCARD\n loadDocument(kb, VCARD_ONTOLOGY_TEXT, vcardName, vcardOntUri)\n\n try {\n await kb.fetcher.load(subject.doc())\n } catch (err) {\n debug.error('Error loading profile card. Stack: ' + err)\n throw new Error('Failed to load profile card.')\n } // end of try catch on load\n\n div.classList.add('individualPane')\n\n authn.checkUser() // kick off async operation @@@ use async version\n\n div.appendChild(renderMugshotGallery(dom, subject))\n\n const whichForm = isOrganization ? 'organizationForm' : 'individualForm'\n\n renderForm(div, subject, formsSource, formsName, store, dom, subject.doc(), whichForm)\n // Improve keyboard navigation: prevent tabbing into label links created by rdflib/solid-ui forms\n skipLabelsFromTabbing(div)\n\n // forward list element from context if available; some callers (such as\n // the contacts pane) attach `ulPeople` so that group membership control can\n // refresh the master list when a membership is removed.\n if (!isAWebID(subject)) {\n div.appendChild(await renderGroupMemberships(\n subject,\n dataBrowserContext,\n dataBrowserContext.ulPeople\n ))\n }\n\n if (authn.currentUser()) {\n // Allow to attach documents etc to the profile card\n // creates a\n const h3 = div.appendChild(dom.createElement('h3'))\n h3.textContent = 'Attach a link to any file'\n h3.classList.add('contactPanedHeading')\n\n UI.widgets.attachmentList(dom, subject, div, {\n modify: editable\n // promptIcon: UI.icons.iconBase + 'noun_681601.svg',\n // predicate: default <http://www.w3.org/2005/01/wf/flow#attachment>\n })\n }\n\n if (isOrganization) {\n div.appendChild(await renderPublicIdControl(subject, dataBrowserContext))\n } else if (!isAWebID(subject)) {\n // Only render WebID control for a contact and not. WebID.\n div.appendChild(await renderWebIdControl(subject, dataBrowserContext))\n }\n} // renderIndividual\n","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./toolsPane.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./toolsPane.css\";\n export default content && content.locals ? content.locals : undefined;\n","// The tools pane is for managing and debugging and maintaining solid contacts databases\nimport * as UI from 'solid-ui'\nimport { store } from 'solid-logic'\nimport { saveNewGroup, addPersonToGroup, groupMembers } from './contactLogic'\nimport './styles/toolsPane.css'\nimport * as $rdf from 'rdflib'\nimport { normalizeGroupUri } from './localUtils'\nimport * as debug from './debug'\n\nconst kb = store\nconst ns = UI.ns\nconst VCARD = ns.vcard\n\nlet book\nlet selectedGroups\nlet logSpace\nlet refreshGroupsFn\n\nexport function toolsPane (\n selectAllGroups,\n selectedGroupsParam,\n groupsMainTable,\n bookParam,\n dataBrowserContext,\n me,\n refreshGroups\n) {\n book = bookParam\n selectedGroups = selectedGroupsParam\n refreshGroupsFn = refreshGroups\n const dom = dataBrowserContext.dom\n\n const pane = dom.createElement('div')\n pane.classList.add('toolsPane')\n\n const settingsHeader = dom.createElement('h3')\n settingsHeader.textContent = 'Tools'\n pane.appendChild(settingsHeader)\n\n const divStatistics = pane.appendChild(dom.createElement('div'))\n divStatistics.classList.add('statsLog')\n\n logSpace = divStatistics.appendChild(dom.createElement('pre'))\n logSpace.setAttribute('id', 'logSpace')\n\n const buttonsContainer = pane.appendChild(dom.createElement('div'))\n buttonsContainer.classList.add('toolsButtonsContainer')\n\n function setActiveButton (activeBtn) {\n const wasActive = activeBtn.classList.contains('btn-primary')\n buttonsContainer.querySelectorAll('button').forEach(btn => {\n btn.classList.remove('btn-primary', 'toolsButton--loading', 'toolsButton--error', 'toolsButton--success')\n btn.classList.add('btn-secondary')\n })\n if (!wasActive) {\n activeBtn.classList.remove('btn-secondary')\n activeBtn.classList.add('btn-primary')\n }\n }\n\n const loadIndexButton = buttonsContainer.appendChild(dom.createElement('button'))\n loadIndexButton.textContent = 'Load main index'\n loadIndexButton.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n loadIndexButton.addEventListener('click', () => {\n setActiveButton(loadIndexButton)\n logSpace.textContent = ''\n loadIndexHandler(loadIndexButton, logSpace)\n })\n\n const statButton = buttonsContainer.appendChild(dom.createElement('button'))\n statButton.textContent = 'Statistics'\n statButton.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n statButton.addEventListener('click', () => {\n setActiveButton(statButton)\n logSpace.textContent = ''\n stats(logSpace)\n })\n\n const checkAccessButton = buttonsContainer.appendChild(dom.createElement('button'))\n checkAccessButton.textContent =\n 'Check individual contact access of selected groups'\n checkAccessButton.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n checkAccessButton.addEventListener('click', (event) => {\n setActiveButton(checkAccessButton)\n logSpace.textContent = ''\n checkAcces(event)\n })\n\n // DUPLICATES CHECK\n const checkDuplicates = buttonsContainer.appendChild(dom.createElement('button'))\n checkDuplicates.textContent = 'Find duplicate contacts'\n checkDuplicates.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n checkDuplicates.addEventListener('click', function (_event) {\n setActiveButton(checkDuplicates)\n logSpace.textContent = ''\n const stats = {} // global god context\n\n stats.book = book\n stats.nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))\n log(logSpace, 'Loading name index...')\n\n store.fetcher.nowOrWhenFetched(\n stats.nameEmailIndex,\n undefined,\n function (_ok, _message) {\n log(logSpace, 'Loaded name index.')\n\n stats.cards = []\n stats.duplicates = []\n stats.definitive = []\n stats.nameless = []\n\n stats.exactDuplicates = []\n stats.nameOnlyDuplicates = []\n\n stats.uniquesSet = []\n stats.groupProblems = []\n\n // Erase one card and all its files -> (err)\n //\n /*\n function eraseOne (card) {\n return new Promise(function (resolve, reject) {\n function removeFromMainIndex () {\n var indexBit = kb.connectedStatements(card, stats.nameEmailIndex)\n log(logSpace, 'Bits of the name index file:' + indexBit)\n log(logSpace, 'Patching main index file...')\n kb.updater.update(indexBit, [], function (uri, ok, body) {\n if (ok) {\n log(logSpace, 'Success')\n resolve(null)\n } else {\n log(logSpace, 'Error patching index file! ' + body)\n reject('Error patching index file! ' + body)\n }\n })\n }\n var filesToDelete = [ card.doc() ]\n var photos = kb.each(card, ns.vcard('hasPhoto')) // could be > 1\n if (photos.length) {\n filesToDelete = filesToDelete.concat(photos)\n }\n filesToDelete.push(card.dir()) // the folder last\n log(logSpace, 'Files to delete: ' + filesToDelete)\n if (!await confirmDialog('DELETE card ' + card.dir() + ' for \"' + kb.any(card, VCARD('fn')) + '\", with ' + kb.each(card).length + 'statements?')) {\n return resolve('Cancelled by user')\n }\n\n function deleteNextFile () {\n var resource = filesToDelete.shift()\n if (!resource) {\n log(logSpace, 'All deleted')\n removeFromMainIndex()\n resolve()\n }\n log(logSpace, 'Deleting ... ' + resource)\n kb.fetcher.delete(resource)\n .then(function () {\n log(logSpace, 'Deleted ok: ' + resource)\n deleteNextFile()\n })\n .catch(function (e) {\n var err = '*** ERROR deleting ' + resource + ': ' + e\n log(logSpace, err)\n if (await confirmDialog('Patch out index file for card ' + card.dir() + ' EVEN THOUGH card DELETE errors?')) {\n removeFromMainIndex()\n } else {\n reject(err)\n }\n })\n }\n deleteNextFile()\n }) // Promise\n } // erase one\n*/\n // Check actual records to see which are exact matches - slow\n stats.nameDupLog = kb.sym(book.dir().uri + 'dedup-nameDupLog.ttl')\n stats.exactDupLog = kb.sym(book.dir().uri + 'dedup-exactDupLog.ttl')\n /*\n function checkOne (card) {\n return new Promise(function (resolve, reject) {\n var name = kb.anyValue(card, ns.vcard('fn'))\n var other = stats.definitive[name]\n kb.fetcher.load([card, other]).then(function (xhrs) {\n var exclude = {}\n exclude[ns.vcard('hasUID').uri] = true\n exclude[ns.dc('created').uri] = true\n exclude[ns.dc('modified').uri] = true\n function filtered (x) {\n return kb.statementsMatching(null, null, null, x.doc()).filter(function (st) {\n return !exclude[st.predicate.uri]\n })\n }\n var desc = filtered(card)\n var desc2 = filtered(other)\n // var desc = connectedStatements(card, card.doc(), exclude)\n // var desc2 = connectedStatements(other, other.doc(), exclude)\n if (desc.length !== desc2.length) {\n log(logSpace, 'CARDS to NOT match lengths ')\n stats.nameOnlyDuplicates.push(card)\n return resolve(false)\n }\n if (!desc.length) {\n log(logSpace, '@@@@@@ Zero length ')\n stats.nameOnlyDuplicates.push(card)\n return resolve(false)\n }\n // //////// Compare the two\n // Cheat: serialize and compare\n // var cardText = $rdf.serialize(card.doc(), kb, card.doc().uri, 'text/turtle')\n // var otherText = $rdf.serialize(other.doc(), kb, other.doc().uri, 'text/turtle')\n var cardText = (new $rdf.Serializer(kb)).setBase(card.doc().uri).statementsToN3(desc)\n var otherText = (new $rdf.Serializer(kb)).setBase(other.doc().uri).statementsToN3(desc2)\n //\n // log('Name: ' + name + ', statements: ' + desc.length)\n // log('___________________________________________')\n // log('KEEPING: ' + other.doc() + '\\n' + cardText)\n // log('___________________________________________')\n // log('DELETING: '+ card.doc() + '\\n' + otherText)\n // log('___________________________________________')\n //\n if (cardText !== otherText) {\n log(logSpace, 'Texts differ')\n stats.nameOnlyDuplicates.push(card)\n return resolve(false)\n }\n var cardGroups = kb.each(null, ns.vcard('hasMember'), card)\n var otherGroups = kb.each(null, ns.vcard('hasMember'), other)\n for (var j = 0; j < cardGroups.length; j++) {\n var found = false\n for (var k = 0; k < otherGroups.length; k++) {\n if (otherGroups[k].sameTerm(cardGroups[j])) { found = true }\n }\n if (!found) {\n log(logSpace, 'This one groups: ' + cardGroups)\n log(logSpace, 'Other one groups: ' + otherGroups)\n log(logSpace, 'Cant delete this one because it has a group, ' + cardGroups[j] + ', which the other does not.')\n stats.nameOnlyDuplicates.push(card)\n return resolve(false)\n }\n }\n debug.log('Group check done -- exact duplicate: ' + card)\n stats.exactDuplicates.push(card)\n resolve(true)\n }).catch(function (e) {\n log(logSpace, 'Cant load a card! ' + [card, other] + ': ' + e)\n stats.nameOnlyDuplicates.push(card)\n resolve(false)\n // if (await confirmDialog('Patch out index file for card ' + card.dir() + ' EVEN THOUGH card READ errors?')){\n // removeFromMainIndex()\n // }\n })\n })\n } // checkOne\n*/\n stats.nameOnlyErrors = []\n stats.nameLessZeroData = []\n stats.nameLessIndex = []\n stats.namelessUniques = []\n stats.nameOnlyDuplicatesGroupDiff = []\n\n function checkOneNameless (card) {\n return new Promise(function (resolve) {\n kb.fetcher\n .load(card)\n .then(function (_xhr) {\n log(logSpace, ' Nameless check ' + card)\n const exclude = {}\n exclude[ns.vcard('hasUID').uri] = true\n exclude[ns.dc('created').uri] = true\n exclude[ns.dc('modified').uri] = true\n function filtered (x) {\n return kb\n .statementsMatching(null, null, null, x.doc())\n .filter(function (st) {\n return !exclude[st.predicate.uri]\n })\n }\n\n const desc = filtered(card)\n // var desc = connectedStatements(card, card.doc(), exclude)\n // var desc2 = connectedStatements(other, other.doc(), exclude)\n if (!desc.length) {\n log(logSpace, ' Zero length ' + card)\n stats.nameLessZeroData.push(card)\n return resolve(false)\n }\n // Compare the two\n // Cheat: serialize and compare\n // var cardText = $rdf.serialize(card.doc(), kb, card.doc().uri, 'text/turtle')\n // var otherText = $rdf.serialize(other.doc(), kb, other.doc().uri, 'text/turtle')\n const cardText = new $rdf.Serializer(kb)\n .setBase(card.doc().uri)\n .statementsToN3(desc)\n const other = stats.nameLessIndex[cardText]\n if (other) {\n log(logSpace, ' Matches with ' + other)\n // alain not sure it works we may need to concat with 'sameAs' group.doc (.map(st => st.why))\n const cardGroups = kb.each(null, ns.vcard('hasMember'), card)\n const otherGroups = kb.each(null, ns.vcard('hasMember'), other)\n for (let j = 0; j < cardGroups.length; j++) {\n let found = false\n for (let k = 0; k < otherGroups.length; k++) {\n if (otherGroups[k].sameTerm(cardGroups[j])) found = true\n }\n if (!found) {\n log(logSpace, 'This one groups: ' + cardGroups)\n log(logSpace, 'Other one groups: ' + otherGroups)\n log(\n logSpace,\n 'Cant skip this one because it has a group, ' +\n cardGroups[j] +\n ', which the other does not.'\n )\n stats.nameOnlyDuplicatesGroupDiff.push(card)\n return resolve(false)\n }\n }\n debug.log('Group check done -- exact duplicate: ' + card)\n } else {\n log(logSpace, 'First nameless like: ' + card.doc())\n log(logSpace, '___________________________________________')\n log(logSpace, cardText)\n log(logSpace, '___________________________________________')\n stats.nameLessIndex[cardText] = card\n stats.namelessUniques.push(card)\n }\n resolve(true)\n })\n .catch(function (e) {\n log(logSpace, 'Cant load a nameless card!: ' + e)\n stats.nameOnlyErrors.push(card)\n resolve(false)\n })\n })\n } // checkOneNameless\n\n function checkAllNameless () {\n stats.namelessToCheck =\n stats.namelessToCheck || stats.nameless.slice()\n log(logSpace, 'Nameless check left: ' + stats.namelessToCheck.length)\n return new Promise(function (resolve) {\n const x = stats.namelessToCheck.shift()\n if (!x) {\n log(logSpace, 'namelessUniques: ' + stats.namelessUniques.length)\n log(logSpace, 'namelessUniques: ' + stats.namelessUniques)\n if (stats.namelessUniques.length > 0) {\n const msg = dom.createElement('p')\n msg.textContent = 'Add all ' + stats.namelessUniques.length + ' nameless contacts to the rescued set?'\n divStatistics.appendChild(msg)\n const confirmButton = UI.widgets.continueButton(dom, function () {\n stats.uniques = stats.uniques.concat(stats.namelessUniques)\n for (let k = 0; k < stats.namelessUniques.length; k++) {\n stats.uniqueSet[stats.namelessUniques[k].uri] = true\n }\n msg.remove()\n confirmButton.remove()\n resolve(true)\n })\n divStatistics.appendChild(confirmButton)\n } else {\n return resolve(true)\n }\n return\n }\n checkOneNameless(x).then(function (exact) {\n log(logSpace, ' Nameless check returns ' + exact)\n checkAllNameless() // loop\n })\n })\n }\n\n function checkGroupMembers () {\n return new Promise(function (resolve) {\n // var inUniques = 0\n log(logSpace, 'Groups loaded')\n for (let i = 0; i < stats.uniques.length; i++) {\n stats.uniquesSet[stats.uniques[i].uri] = true\n }\n stats.groupMembers = []\n kb.each(null, ns.vcard('hasMember'))\n .forEach(group => { stats.groupMembers = stats.groupMembers.concat(groupMembers(kb, group)) })\n log(logSpace, ' Naive group members ' + stats.groupMembers.length)\n stats.groupMemberSet = []\n for (let j = 0; j < stats.groupMembers.length; j++) {\n stats.groupMemberSet[stats.groupMembers[j].uri] =\n stats.groupMembers[j]\n }\n stats.groupMembers2 = []\n for (const g in stats.groupMemberSet) {\n stats.groupMembers2.push(stats.groupMemberSet[g])\n }\n log(logSpace, ' Compact group members ' + stats.groupMembers2.length)\n\n if (\n $rdf.keepThisCodeForLaterButDisableFerossConstantConditionPolice\n ) {\n // Don't inspect as seems groups membership is complete\n for (let i = 0; i < stats.groupMembers.length; i++) {\n const card = stats.groupMembers[i]\n if (stats.uniquesSet[card.uri]) {\n // inUniques += 1\n } else {\n log(logSpace, ' Not in uniques: ' + card)\n stats.groupProblems.push(card)\n if (stats.duplicateSet[card.uri]) {\n log(logSpace, ' ** IN duplicates alas:' + card)\n } else {\n log(logSpace, ' **** WTF?')\n }\n }\n }\n log(logSpace, 'Problem contacts: ' + stats.groupProblems.length)\n } // if\n resolve(true)\n })\n } // checkGroupMembers\n\n function scanForDuplicates () {\n return new Promise(function (resolve) {\n stats.cards = kb.each(undefined, VCARD('inAddressBook'), stats.book)\n log(logSpace, '' + stats.cards.length + ' total contacts')\n\n let c, card, name\n for (c = 0; c < stats.cards.length; c++) {\n card = stats.cards[c]\n name = kb.anyValue(card, ns.vcard('fn'))\n if (!name) {\n stats.nameless.push(card)\n continue\n }\n if (stats.definitive[name] === card) {\n // pass\n } else if (stats.definitive[name]) {\n const n = stats.duplicates.length\n if (n < 100 || (n < 1000 && n % 10 === 0) || n % 100 === 0) {\n // log('' + n + ') Possible duplicate ' + card + ' of: ' + definitive[name])\n }\n stats.duplicates.push(card)\n } else {\n stats.definitive[name] = card\n }\n }\n\n stats.duplicateSet = []\n for (let i = 0; i < stats.duplicates.length; i++) {\n stats.duplicateSet[stats.duplicates[i].uri] = stats.duplicates[i]\n }\n stats.namelessSet = []\n for (let i = 0; i < stats.nameless.length; i++) {\n stats.namelessSet[stats.nameless[i].uri] = stats.nameless[i]\n }\n stats.uniques = []\n stats.uniqueSet = []\n for (let i = 0; i < stats.cards.length; i++) {\n const uri = stats.cards[i].uri\n if (!stats.duplicateSet[uri] && !stats.namelessSet[uri]) {\n stats.uniques.push(stats.cards[i])\n stats.uniqueSet[uri] = stats.cards[i]\n }\n }\n log(logSpace, 'Uniques: ' + stats.uniques.length)\n\n log(logSpace, '' + stats.nameless.length + ' nameless contacts.')\n log(\n logSpace,\n '' +\n stats.duplicates.length +\n ' name-duplicate contacts, leaving ' +\n (stats.cards.length - stats.duplicates.length)\n )\n resolve(true)\n })\n }\n\n // Save a new clean version\n function saveCleanPeople () {\n let cleanPeople\n\n return Promise.resolve()\n .then(() => {\n cleanPeople = kb.sym(stats.book.dir().uri + 'clean-people.ttl')\n let sts = []\n for (let i = 0; i < stats.uniques.length; i++) {\n sts = sts.concat(\n kb.connectedStatements(stats.uniques[i], stats.nameEmailIndex)\n )\n }\n const sz = new $rdf.Serializer(kb).setBase(stats.nameEmailIndex.uri)\n log(logSpace, 'Serializing index of uniques...')\n const data = sz.statementsToN3(sts)\n\n return kb.fetcher.webOperation('PUT', cleanPeople, {\n data,\n contentType: 'text/turtle'\n })\n })\n .then(function () {\n log(logSpace, 'Done uniques log ' + cleanPeople)\n return true\n })\n .catch(function (e) {\n log(logSpace, 'Error saving uniques: ' + e)\n })\n }\n\n function saveCleanGroup (g) {\n let cleanGroup\n\n return Promise.resolve()\n .then(() => {\n const s = g.uri.replace('/Group/', '/NewGroup/')\n cleanGroup = kb.sym(s)\n let sts = []\n for (let i = 0; i < stats.uniques.length; i++) {\n sts = sts.concat(\n kb.connectedStatements(stats.uniques[i], g.doc())\n )\n }\n const sz = new $rdf.Serializer(kb).setBase(g.uri)\n log(logSpace, ' Regenerating group of uniques...' + cleanGroup)\n const data = sz.statementsToN3(sts)\n\n return kb.fetcher.webOperation('PUT', cleanGroup, {\n data,\n contentType: 'text/turtle'\n })\n })\n .then(() => {\n log(logSpace, ' Done uniques group ' + cleanGroup)\n return true\n })\n .catch(e => {\n log(logSpace, 'Error saving : ' + e)\n })\n }\n\n function saveAllGroups () {\n log(logSpace, 'Saving ALL GROUPS')\n return Promise.all(stats.groupObjects.map(saveCleanGroup))\n }\n\n const getAndSortGroups = function () {\n let groups = []\n if (stats.book) {\n const books = [stats.book]\n books.forEach(function (book) {\n const gs = book ? kb.each(book, ns.vcard('includesGroup')) : []\n const gs2 = gs.map(function (g) {\n return [book, kb.any(g, ns.vcard('fn')), g]\n })\n groups = groups.concat(gs2)\n })\n groups.sort()\n }\n return groups\n }\n const groups = getAndSortGroups() // Needed?\n\n stats.groupObjects = groups.map(gstr => gstr[2])\n log(logSpace, 'Loading ' + stats.groupObjects.length + ' groups... ')\n kb.fetcher\n .load(stats.groupObjects)\n .then(scanForDuplicates)\n .then(checkGroupMembers)\n .then(checkAllNameless)\n .then(saveCleanPeople)\n .then(saveAllGroups)\n .then(function () {\n log(logSpace, 'Done!')\n })\n }\n )\n })\n\n const checkGroupless = buttonsContainer.appendChild(dom.createElement('button'))\n checkGroupless.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n checkGroupless.textContent = 'Find contacts with no group'\n checkGroupless.addEventListener('click', function (_event) {\n setActiveButton(checkGroupless)\n logSpace.textContent = ''\n log(logSpace, 'Loading groups...')\n selectAllGroups(selectedGroups, groupsMainTable, async function (ok, message) {\n if (!ok) {\n log(logSpace, 'Loading all groups failed. If it persists, contact your admin.')\n return\n }\n\n const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))\n try {\n await kb.fetcher.load(nameEmailIndex)\n } catch (e) {\n debug.error('Error loading name index (vcard(nameEmailIndex)). Stack: ' + e)\n log(logSpace, 'Loading name index failed. If it persists, contact your admin.')\n return\n }\n log(logSpace, 'Loaded groups and name index.')\n getGroupless(book)\n log(logSpace, 'Groupless list finished.')\n }) // select all groups then\n })\n\n const fixGrouplessButton = buttonsContainer.appendChild(dom.createElement('button'))\n fixGrouplessButton.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n fixGrouplessButton.textContent = 'Put all individuals with no group in a new group'\n fixGrouplessButton.addEventListener('click', _event => {\n setActiveButton(fixGrouplessButton)\n logSpace.textContent = ''\n fixGroupless(book)\n })\n\n // this is an old not needed anymore fix from https://github.com/SolidOS/contacts-pane/issues/81\n /*\n const fixToOldDataModelButton = buttonsContainer.appendChild(dom.createElement('button'))\n fixToOldDataModelButton.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n fixToOldDataModelButton.textContent = 'Revert groups to old data model'\n fixToOldDataModelButton.addEventListener('click', _event => {\n setActiveButton(fixToOldDataModelButton)\n logSpace.textContent = ''\n fixToOldDataModel(book)\n })\n */\n return pane\n}\n\nasync function checkAcces (_event) {\n function doCard (card) {\n UI.acl.fixIndividualCardACL(card, (msg) => log(logSpace, msg), function (ok, message) {\n if (ok) {\n log(logSpace, 'Success for ' + UI.utils.label(card))\n } else {\n debug.error('Failure for ' + card + ': ' + message)\n log(logSpace, 'Failure for ' + card + ': ' + message)\n }\n })\n }\n const gg = []\n for (const g in selectedGroups) {\n gg.push(g)\n }\n\n for (let i = 0; i < gg.length; i++) {\n const g = kb.sym(gg[i])\n const a = groupMembers(kb, g)\n log(logSpace, UI.utils.label(g) + ': ' + a.length + ' members')\n for (let j = 0; j < a.length; j++) {\n const card = a[j]\n log(logSpace, UI.utils.label(card))\n doCard(card)\n }\n }\n}\n\nfunction log (logSpace, message) {\n logSpace.textContent += message + '\\n'\n}\n\nfunction stats (logSpace) {\n const totalContacts = kb.each(undefined, VCARD('inAddressBook'), book).length\n log(logSpace, '' + totalContacts + ' contacts loaded. ')\n let groups = kb.each(book, VCARD('includesGroup'))\n const strings = new Set(groups.map(group => normalizeGroupUri(group.uri))) // remove dups with normalized URIs\n groups = [...strings].map(uri => kb.sym(uri))\n log(logSpace, '' + groups.length + ' total groups. ')\n const gg = []\n for (const g in selectedGroups) {\n gg.push(g)\n }\n log(logSpace, '' + gg.length + ' selected groups. ')\n}\n\nasync function loadIndexHandler (loadIndexButton, logSpace) {\n loadIndexButton.classList.add('toolsButton--loading')\n loadIndexButton.classList.remove('toolsButton--error', 'toolsButton--success')\n const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))\n try {\n await kb.fetcher.load(nameEmailIndex)\n } catch (e) {\n loadIndexButton.classList.remove('toolsButton--loading')\n loadIndexButton.classList.add('toolsButton--error')\n log(logSpace, 'Error: People index has NOT been loaded' + e + '\\n')\n }\n loadIndexButton.classList.remove('toolsButton--loading')\n loadIndexButton.classList.add('toolsButton--success')\n log(logSpace, ' People index has been loaded\\n')\n} // loadIndexHandler\n\nasync function fixGroupless (book) {\n const groupless = await getGroupless(book)\n if (groupless.length === 0) {\n log(logSpace, 'No groupless contacts found.')\n return\n }\n let groupOfUngrouped = null\n try {\n groupOfUngrouped = await saveNewGroup(book, 'No group')\n } catch (_e) {\n // do nothing\n }\n\n const dom = logSpace.ownerDocument\n return new Promise(function (resolve) {\n const msg = dom.createElement('p')\n msg.textContent = `Add the ${groupless.length} contacts without groups to a 'No group' group?`\n logSpace.appendChild(msg)\n const confirmButton = UI.widgets.continueButton(dom, async function () {\n msg.remove()\n confirmButton.remove()\n for (const person of groupless) {\n if (groupOfUngrouped) {\n log(logSpace, ' adding ' + UI.utils.label(person))\n await addPersonToGroup(person, groupOfUngrouped)\n }\n }\n log(logSpace, 'People moved to group.')\n if (refreshGroupsFn) refreshGroupsFn()\n resolve()\n })\n logSpace.appendChild(confirmButton)\n })\n}\n\nasync function getGroupless (book) {\n const groupIndex = kb.any(book, ns.vcard('groupIndex'))\n const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))\n try {\n await kb.fetcher.load([nameEmailIndex, groupIndex])\n const groups = kb.each(book, ns.vcard('includesGroup'))\n await kb.fetcher.load(groups)\n } catch (e) {\n debug.error('Error loading groups. Stack: ' + e)\n log(logSpace, 'Error loading groups or name index. If it persists, contact your admin.')\n }\n\n const reverseIndex = {}\n const groupless = []\n let groups = kb.each(book, VCARD('includesGroup'))\n const strings = new Set(groups.map(group => normalizeGroupUri(group.uri))) // remove dups with normalized URIs\n groups = [...strings].map(uri => kb.sym(uri))\n log(logSpace, '' + groups.length + ' total groups. ')\n\n for (let i = 0; i < groups.length; i++) {\n const g = groups[i]\n const a = groupMembers(kb, g)\n\n log(logSpace, UI.utils.label(g) + ': ' + a.length + ' members')\n for (let j = 0; j < a.length; j++) {\n kb.allAliases(a[j]).forEach(function (y) {\n reverseIndex[y.uri] = g\n })\n }\n }\n\n const cards = kb.each(undefined, VCARD('inAddressBook'), book)\n log(logSpace, '' + cards.length + ' total contatcs')\n for (let c = 0; c < cards.length; c++) {\n if (!reverseIndex[cards[c].uri]) {\n groupless.push(cards[c])\n log(logSpace, ' groupless ' + UI.utils.label(cards[c]))\n }\n }\n log(logSpace, '' + groupless.length + ' groupless contacts.')\n return groupless\n}\n\n/*\nasync function fixToOldDataModel (book) {\n async function updateToOldDataModel (groups) {\n let ds = []\n let ins = []\n groups.forEach(group => {\n let vcardOrWebids = kb.statementsMatching(null, ns.owl('sameAs'), null, group.doc()).map(st => st.subject)\n const strings = new Set(vcardOrWebids.map(contact => contact.uri)) // remove dups\n vcardOrWebids = [...strings].map(uri => kb.sym(uri))\n vcardOrWebids.forEach(item => {\n if (!kb.each(item, ns.vcard('fn'), null, group.doc()).length) {\n // delete item this is a new data model, item is a webid not a card.\n ds = ds.concat(kb\n .statementsMatching(item, ns.owl('sameAs'), null, group.doc())\n .concat(kb.statementsMatching(undefined, undefined, item, group.doc())))\n // add webid card to group\n const cards = kb.each(item, ns.owl('sameAs'), null, group.doc())\n cards.forEach(card => {\n ins = ins.concat($rdf.st(card, ns.owl('sameAs'), item, group.doc()))\n .concat($rdf.st(group, ns.vcard('hasMember'), card, group.doc()))\n })\n }\n })\n })\n if (ds.length) {\n const dom = logSpace.ownerDocument\n return new Promise(function (resolve) {\n const msg = dom.createElement('p')\n msg.textContent = 'Groups can be updated to old data model?'\n logSpace.appendChild(msg)\n const confirmButton = UI.widgets.continueButton(dom, async function () {\n msg.remove()\n confirmButton.remove()\n await kb.updater.updateMany(ds, ins)\n log(logSpace, 'Update done')\n resolve()\n })\n logSpace.appendChild(confirmButton)\n })\n } else {\n log(logSpace, 'Nothing to update.\\nAll groups already use the old data model.')\n }\n }\n let groups = kb.each(book, VCARD('includesGroup'))\n const strings = new Set(groups.map(group => normalizeGroupUri(group.uri))) // remove dups with normalized URIs\n groups = [...strings].map(uri => kb.sym(uri))\n updateToOldDataModel(groups)\n}\n */\n","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./utilities.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./utilities.css\";\n export default content && content.locals ? content.locals : undefined;\n","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./contactsPane.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./contactsPane.css\";\n export default content && content.locals ? content.locals : undefined;\n","/* Contact AddressBook Pane\n**\n** This outline pane allows a user to interact with a contact,\nto change its state according to an ontology, comment on it, etc.\n**\n** See also things like\n** http://www.w3.org/TR/vcard-rdf/\n** http://tools.ietf.org/html/rfc6350\n** http://www.iana.org/assignments/vcard-elements/vcard-elements.xhtml\n**\n*/\n\nimport { authn } from 'solid-logic'\nimport { saveNewContact, saveNewGroup } from './contactLogic'\nimport * as UI from 'solid-ui'\nimport { mintNewAddressBook } from './mintNewAddressBook'\nimport { renderIndividual } from './individual'\nimport { toolsPane } from './toolsPane'\nimport './styles/utilities.css'\nimport './styles/contactsPane.css'\nimport {\n checkDataModel, ensureBookLoaded, renderGroupButtons,\n refreshThingsSelected, refreshNames, selectAllGroups, loadAllGroups,\n syncGroupUl, setActiveGroupButton, createGroupLi, refreshFilteredPeople,\n deselectAllPeople, handleURIsDroppedOnGroup\n} from './addressBookPresenter'\nimport { alertDialog, complain, deleteThingAndDoc, setDom, setupResponsiveStacking } from './localUtils'\nimport * as debug from './debug'\nimport './styles/contactsRDFFormsEnforced.css'\n\nconst ns = UI.ns\nconst utils = UI.utils\n\nexport default {\n icon: UI.icons.iconBase + 'noun_99101.svg', // changed from embedded icon 2016-05-01\n\n name: 'contact',\n\n // Does the subject deserve a contact pane?\n label: function (subject, context) {\n const t = context.session.store.findTypeURIs(subject)\n if (t[ns.vcard('Individual').uri]) return 'Contact'\n if (t[ns.vcard('Organization').uri]) return 'Contact'\n if (t[ns.foaf('Person').uri]) return 'Person'\n if (t[ns.schema('Person').uri]) return 'Person'\n if (t[ns.vcard('Group').uri]) return 'Group'\n if (t[ns.vcard('AddressBook').uri]) return 'Address book'\n return null // No, under other circumstances\n },\n\n mintClass: UI.ns.vcard('AddressBook'),\n\n mintNew: mintNewAddressBook, // Make a new address book\n\n // Render the pane\n render: function (subject, dataBrowserContext, paneOptions = {}) {\n /*\n function newAddressBookButton (thisAddressBook) {\n return UI.login.newAppInstance(\n dom,\n { noun: 'address book', appPathSegment: 'contactorator.timbl.com' },\n function (ws, newBase) {\n thisPane.mintNew(thisAddressBook, newBase, {\n me,\n div,\n dom\n })\n }\n )\n } */\n\n const dom = dataBrowserContext.dom\n const kb = dataBrowserContext.session.store\n const div = dom.createElement('div')\n setDom(dom) // set dom for ana error handling in other modules\n\n UI.aclControl.preventBrowserDropEvents(dom) // protect drag and drop\n\n div.setAttribute('class', 'contactPane')\n // Make the pane stack vertically (sidebar -> details) when narrow\n // Set breakpoint to 1000 so it triggers at 980 width too.\n setupResponsiveStacking(div, 1000)\n\n asyncRender().then(\n () => debug.log('Contacts pane rendered for ' + subject),\n err => complain(div, dom, err.message || '' + err)\n ).catch(err => {\n complain(div, dom, err.message || '' + err)\n })\n return div\n\n // Async part of render. Maybe API will later allow render to be async\n async function asyncRender () {\n UI.aclControl.preventBrowserDropEvents(dom)\n\n const t = kb.findTypeURIs(subject)\n\n // Render a single contact Individual\n if (\n t[ns.vcard('Individual').uri] ||\n t[ns.foaf('Person').uri] ||\n t[ns.schema('Person').uri] ||\n t[ns.vcard('Organization').uri] ||\n t[ns.schema('Organization').uri]\n ) {\n try {\n await renderIndividual(dom, div, subject, dataBrowserContext)\n } catch (err) {\n debug.error('Error rendering contact. Stack: ' + err)\n throw new Error('Failed to render contact: ' + (err.message || err))\n }\n /*\n // Render a Group instance\n }\n else if (t[ns.vcard('Group').uri]) {\n // If we have a main address book, then render this group as a guest group within it\n UI.login\n .findAppInstances(context, ns.vcard('AddressBook'))\n .then(function (context) {\n const addressBooks = context.instances\n const options = { foreignGroup: subject }\n if (addressBooks.length > 0) {\n // const book = addressBooks[0]\n renderAddressBook(addressBooks, options)\n } else {\n renderAddressBook([], options)\n // @@ button to Make a new addressBook\n }\n })\n .catch(function (e) {\n complain(div, dom, '' + e)\n })\n */\n // Render a AddressBook instance\n } else if (t[ns.vcard('AddressBook').uri]) {\n renderAddressBook([subject], {})\n } else {\n debug.error('No evidence that ' + subject + ' is anything to do with contacts.')\n throw new Error('This does not seem to be a contact or address book.')\n }\n\n let me = authn.currentUser()\n\n // Render AddressBook instance\n function renderAddressBook (books, options) {\n kb.fetcher\n .load(books)\n .then(function (_xhr) {\n renderAddressBookDetails(books, options)\n })\n .catch(function (err) {\n debug.error('Error loading address book. Stack: ' + err)\n throw new Error('Failed to load address book.')\n })\n }\n\n function renderAddressBookDetails (books, options) {\n const classLabel = utils.label(ns.vcard('AddressBook'))\n\n let book = options.foreignGroup // in case we have only a Grouo\n let title = ''\n if (books && books.length > 0) {\n book = books[0] // if we have an Address Book, we prefer this\n title = utils.label(book.dir())\n } else {\n kb.any(book, ns.dc('title')) || kb.any(book, ns.vcard('fn'))\n if (paneOptions.solo && title && typeof document !== 'undefined') {\n document.title = title.value // @@ only when the outermmost pane\n }\n title = title ? title.value : classLabel\n }\n\n const groupIndex = kb.any(book, ns.vcard('groupIndex'))\n const selectedGroups = {}\n let selectedPeople = {} // Actually prob max 1\n\n let allGroupsLi = null\n let newGroupLi = null\n\n // Centralized active-button tracking across all action buttons\n const actionButtons = []\n function setActiveActionButton (activeBtn) {\n actionButtons.forEach(btn => {\n btn.classList.remove('btn-primary')\n btn.classList.add('btn-secondary')\n })\n if (activeBtn) {\n activeBtn.classList.remove('btn-secondary')\n activeBtn.classList.add('btn-primary')\n }\n }\n\n // Shared context passed to all builder functions\n const ctx = {\n dom,\n kb,\n ns,\n book,\n options,\n title,\n groupIndex,\n selectedGroups,\n get selectedPeople () { return selectedPeople },\n set selectedPeople (v) { selectedPeople = v },\n get allGroupsLi () { return allGroupsLi },\n set allGroupsLi (v) { allGroupsLi = v },\n get newGroupLi () { return newGroupLi },\n set newGroupLi (v) { newGroupLi = v },\n actionButtons,\n setActiveActionButton,\n dataBrowserContext,\n div,\n me,\n setMe (v) { me = v },\n paneOptions,\n }\n\n // ── Build layout ────────────────────────────────────────────\n const { main, addressBookSection, detailsSection } = buildMainLayout(ctx)\n div.appendChild(main)\n\n function showDetailsSection () {\n detailsSection.classList.remove('hidden')\n }\n ctx.showDetailsSection = showDetailsSection\n ctx.detailsSection = detailsSection\n\n // Create shared DOM elements needed by multiple builders\n const ulPeople = dom.createElement('ul')\n ulPeople.setAttribute('role', 'list')\n ulPeople.setAttribute('aria-label', 'People list')\n ctx.ulPeople = ulPeople\n // make the element available on the dataBrowserContext too; other\n // modules (individual/group membership) look for this property when\n // they need to refresh the master list after a mutation.\n if (ctx.dataBrowserContext) ctx.dataBrowserContext.ulPeople = ulPeople\n\n const detailsSectionContent = dom.createElement('div')\n detailsSectionContent.classList.add('detailsSectionContent')\n detailsSectionContent.setAttribute('role', 'region')\n detailsSectionContent.setAttribute('aria-labelledby', 'detailsSectionContent')\n detailsSectionContent.setAttribute('aria-live', 'polite')\n ctx.detailsSectionContent = detailsSectionContent\n\n // ── Header (title + New Contact button) ─────────────────────\n const headerSection = buildHeaderSection(ctx)\n addressBookSection.appendChild(headerSection)\n\n const dottedHr = dom.createElement('hr')\n dottedHr.classList.add('dottedHr')\n addressBookSection.appendChild(dottedHr)\n\n // ── Search ──────────────────────────────────────────────────\n const { searchSection, searchInput } = buildSearchSection(ctx)\n ctx.searchInput = searchInput\n addressBookSection.appendChild(searchSection)\n\n // ── Group bar ───────────────────────────────────────────────\n const { buttonSection, ulGroups } = buildGroupBar(ctx)\n ctx.ulGroups = ulGroups\n addressBookSection.appendChild(buttonSection)\n\n // ── People list ─────────────────────────────────────────────\n const peopleListSection = dom.createElement('section')\n peopleListSection.classList.add('peopleSection')\n addressBookSection.appendChild(peopleListSection)\n peopleListSection.appendChild(ulPeople)\n\n // ── Details content section ─────────────────────────────────\n detailsSection.appendChild(detailsSectionContent)\n\n // ── Footer buttons ──────────────────────────────────────────\n const cardFooter = buildFooterButtons(ctx)\n addressBookSection.appendChild(cardFooter)\n\n checkDataModel(book, detailsSectionContent).then(() => { debug.log('Async checkDataModel done.') })\n }\n\n // /////////////// Fix user when testing on a plane\n\n if (\n typeof document !== 'undefined' &&\n document.location &&\n ('' + document.location).slice(0, 16) === 'http://localhost'\n ) {\n const inferredOwner = kb.any(subject, UI.ns.acl('owner')) // when testing on plane with no webid\n if (inferredOwner) {\n me = inferredOwner\n }\n }\n\n return div\n } // asyncRender\n } // render function\n} // pane object\n\n// ── Helper: handle \"New group\" button click ──────────────────────────\nasync function handleNewGroupClick (ctx) {\n const { dom, kb, ns, book, options, selectedGroups, dataBrowserContext } = ctx\n ctx.showDetailsSection()\n ctx.detailsSectionContent.innerHTML = ''\n const groupIndex = kb.any(book, ns.vcard('groupIndex'))\n try {\n await kb.fetcher.load(groupIndex)\n } catch (e) {\n debug.log('Error: Group index NOT loaded:' + e + '\\n')\n }\n debug.log(' Group index has been loaded\\n')\n\n const name = await UI.widgets.askName(\n dom, kb, ctx.detailsSectionContent, UI.ns.foaf('name'), ns.vcard('Group'), 'group')\n if (!name) return // cancelled by user\n let group\n try {\n group = await saveNewGroup(book, name)\n } catch (err) {\n debug.log('Error: can\\'t save new group:' + err)\n ctx.detailsSectionContent.innerHTML = 'Failed to save group' + err\n return\n }\n for (const key in selectedGroups) delete selectedGroups[key]\n selectedGroups[group.uri] = true\n\n // Refresh the group buttons list\n const allGroupsLi = ctx.allGroupsLi\n const newGroupLi = ctx.newGroupLi\n if (allGroupsLi.parentNode) allGroupsLi.parentNode.removeChild(allGroupsLi)\n if (newGroupLi.parentNode) newGroupLi.parentNode.removeChild(newGroupLi)\n syncGroupUl(book, options, ctx.ulGroups, dom, selectedGroups, ctx.ulPeople, ctx.searchInput)\n ctx.ulGroups.insertBefore(allGroupsLi, ctx.ulGroups.firstChild)\n ctx.ulGroups.appendChild(newGroupLi)\n refreshThingsSelected(ctx.ulGroups, selectedGroups)\n // Highlight the new group button in ulGroups and show empty people list\n const matchingLi = Array.from(ctx.ulGroups.children).find(li => li.subject && li.subject.uri === group.uri)\n setActiveGroupButton(ctx.ulGroups, matchingLi ? matchingLi.querySelector('button') : null)\n refreshNames(ctx.ulPeople, null, false)\n\n ctx.detailsSectionContent.innerHTML = ''\n ctx.detailsSectionContent.appendChild(UI.aclControl.ACLControlBox5(\n group.doc(), dataBrowserContext, 'group', kb,\n function (ok, body) {\n if (!ok) {\n ctx.detailsSectionContent.innerHTML =\n 'Group sharing setup failed: ' + body\n }\n }))\n}\n\n// ── Helper: render askName form for person or organization ───────────\nfunction createNewPersonOrOrganization (ctx, formContainer, klass) {\n const { dom, kb, book, selectedGroups, dataBrowserContext } = ctx\n formContainer.innerHTML = ''\n UI.widgets\n .askName(dom, kb, formContainer, UI.ns.foaf('name'), klass)\n .then(async (name) => {\n if (!name) return // cancelled by user\n ctx.detailsSectionContent.innerHTML = 'Indexing...'\n let person\n try {\n person = await saveNewContact(book, name, selectedGroups, klass)\n } catch (err) {\n const msg = 'Error saving contact. If it persists, contact your admin.'\n alertDialog(msg)\n return\n }\n // It’s possible `saveNewContact` returned `undefined` when no group was\n // selected. In that case we already alerted the user and nothing more\n // should happen.\n if (!person) {\n ctx.detailsSectionContent.innerHTML = ''\n return\n }\n ctx.selectedPeople = {}\n ctx.selectedPeople[person.uri] = true\n refreshNames(ctx.ulPeople, null) // Add name to list of group\n ctx.detailsSectionContent.innerHTML = '' // Clear 'indexing'\n ctx.detailsSectionContent.classList.add('detailsSectionContent--wide')\n const contactPane = dataBrowserContext.session.paneRegistry.byName('contact')\n const paneDiv = contactPane.render(person, dataBrowserContext)\n paneDiv.classList.add('renderPane')\n ctx.detailsSectionContent.appendChild(paneDiv)\n })\n}\n\n// ── Builder: main layout skeleton ────────────────────────────────────\nfunction buildMainLayout (ctx) {\n const { dom } = ctx\n const main = dom.createElement('main')\n main.id = 'main-content'\n main.classList.add('addressBook-grid')\n main.setAttribute('role', 'main')\n main.setAttribute('aria-label', 'Address Book')\n main.setAttribute('tabindex', '-1')\n\n const addressBookSection = dom.createElement('section')\n addressBookSection.setAttribute('aria-labelledby', 'addressBook-section')\n addressBookSection.classList.add('addressBookSection', 'section-bg')\n addressBookSection.setAttribute('role', 'region')\n addressBookSection.setAttribute('tabindex', '-1')\n main.appendChild(addressBookSection)\n\n const detailsSection = dom.createElement('section')\n detailsSection.classList.add('detailSection')\n detailsSection.setAttribute('role', 'region')\n detailsSection.setAttribute('aria-label', 'Details section')\n detailsSection.classList.add('hidden')\n main.appendChild(detailsSection)\n\n return { main, addressBookSection, detailsSection }\n}\n\n// ── Builder: header with title and New Contact button ────────────────\nfunction buildHeaderSection (ctx) {\n const { dom, ns, title, me, setMe, setActiveActionButton } = ctx\n\n const headerSection = dom.createElement('section')\n headerSection.classList.add('headerSection')\n\n const header = dom.createElement('header')\n header.classList.add('mb-md')\n const h2 = dom.createElement('h2')\n h2.id = 'addressBook-heading'\n h2.setAttribute('tabindex', '-1')\n h2.textContent = title\n\n // New Contact button\n const newContactButton = dom.createElement('button')\n const container = dom.createElement('div')\n newContactButton.setAttribute('type', 'button')\n if (!me) newContactButton.setAttribute('disabled', 'true')\n authn.checkUser().then(webId => {\n if (webId) {\n setMe(webId)\n newContactButton.removeAttribute('disabled')\n }\n })\n container.appendChild(newContactButton)\n newContactButton.innerHTML = '+ New contact'\n newContactButton.classList.add('actionButton', 'btn-primary', 'action-button-focus')\n let newContactClickGeneration = 0\n newContactButton.addEventListener('click', async function (_event) {\n setActiveActionButton(null)\n deselectAllPeople(ctx.ulPeople)\n const thisGeneration = ++newContactClickGeneration\n ctx.showDetailsSection()\n ctx.detailsSectionContent.innerHTML = ''\n ctx.detailsSectionContent.classList.remove('detailsSectionContent--wide')\n await ensureBookLoaded()\n // Bail out if a newer click has taken over\n if (thisGeneration !== newContactClickGeneration) return\n ctx.detailsSectionContent.innerHTML = ''\n\n const chooserDiv = dom.createElement('div')\n chooserDiv.classList.add('contactTypeChooser')\n\n const selectLabel = dom.createElement('label')\n selectLabel.textContent = 'Contact type: '\n selectLabel.setAttribute('for', 'contactTypeSelect')\n chooserDiv.appendChild(selectLabel)\n\n const select = dom.createElement('select')\n select.id = 'contactTypeSelect'\n select.classList.add('contactTypeSelect')\n const optIndividual = dom.createElement('option')\n optIndividual.value = 'Individual'\n optIndividual.textContent = 'New person'\n select.appendChild(optIndividual)\n const optOrganization = dom.createElement('option')\n optOrganization.value = 'Organization'\n optOrganization.textContent = 'New organization'\n select.appendChild(optOrganization)\n chooserDiv.appendChild(select)\n\n ctx.detailsSectionContent.appendChild(chooserDiv)\n\n const remark = dom.createElement('p')\n remark.classList.add('contactCreationRemark')\n remark.textContent = 'The new contact is added to the already selected group.'\n ctx.detailsSectionContent.appendChild(remark)\n\n // Container for the askName form, placed below the select\n const formContainer = dom.createElement('div')\n formContainer.classList.add('contactFormContainer')\n ctx.detailsSectionContent.appendChild(formContainer)\n\n function currentKlass () {\n return select.value === 'Organization'\n ? ns.vcard('Organization')\n : ns.vcard('Individual')\n }\n\n // Render person form immediately as default\n createNewPersonOrOrganization(ctx, formContainer, currentKlass())\n\n // Switch form when dropdown changes\n select.addEventListener('change', function () {\n createNewPersonOrOrganization(ctx, formContainer, currentKlass())\n })\n }, false)\n\n // TODO we should also add if it is public or private\n header.appendChild(h2)\n header.appendChild(container)\n headerSection.appendChild(header)\n return headerSection\n}\n\n// ── Builder: search input section ────────────────────────────────────\nfunction buildSearchSection (ctx) {\n const { dom } = ctx\n const searchSection = dom.createElement('section')\n searchSection.classList.add('searchSection')\n const searchDiv = dom.createElement('div')\n searchDiv.classList.add('searchDiv')\n // container for input + clear button\n searchSection.appendChild(searchDiv)\n const searchInput = dom.createElement('input')\n searchInput.setAttribute('type', 'text')\n searchInput.setAttribute('aria-label', 'Search contacts')\n searchInput.classList.add('searchInput')\n searchInput.setAttribute('placeholder', 'Search by name in selected group')\n searchDiv.appendChild(searchInput)\n\n // clear button that appears when there is text\n const clearBtn = dom.createElement('button')\n clearBtn.setAttribute('type', 'button')\n clearBtn.setAttribute('aria-label', 'Clear search')\n clearBtn.classList.add('searchClearButton', 'hidden')\n clearBtn.textContent = '\\u2715' // multiplication sign ×\n searchDiv.appendChild(clearBtn)\n\n searchInput.addEventListener('input', function (_event) {\n const hasText = searchInput.value.length > 0\n // show/hide using the shared \"hidden\" utility class instead of direct\n // style manipulation\n clearBtn.classList.toggle('hidden', !hasText)\n refreshFilteredPeople(ctx.ulPeople, true, ctx.detailsSectionContent)\n })\n\n clearBtn.addEventListener('click', function () {\n searchInput.value = ''\n clearBtn.classList.add('hidden')\n searchInput.focus()\n refreshFilteredPeople(ctx.ulPeople, true, ctx.detailsSectionContent)\n })\n\n return { searchSection, searchInput }\n}\n\n// ── Builder: group buttons bar ───────────────────────────────────────\nfunction buildGroupBar (ctx) {\n const {\n dom, kb, book, options, groupIndex, selectedGroups,\n actionButtons, setActiveActionButton\n } = ctx\n\n const buttonSection = dom.createElement('section')\n buttonSection.classList.add('buttonSection')\n\n const ulGroups = dom.createElement('ul')\n ulGroups.classList.add('groupButtonsList')\n ulGroups.setAttribute('role', 'list')\n ulGroups.setAttribute('aria-label', 'Groups list')\n\n if (options.foreignGroup) {\n selectedGroups[options.foreignGroup.uri] = true\n }\n\n if (book) {\n // All groups button — leftmost, initially selected\n ctx.allGroupsLi = dom.createElement('li')\n const allGroupsButton = dom.createElement('button')\n allGroupsButton.textContent = 'All groups'\n allGroupsButton.classList.add('allGroupsButton', 'actionButton', 'btn-primary', 'action-button-focus', 'allGroupsButton--selected')\n allGroupsButton.addEventListener('click', function (_event) {\n setActiveGroupButton(ulGroups, allGroupsButton)\n setActiveActionButton(null)\n // Check if all groups are currently selected\n const allSelected = Array.from(ulGroups.children).every(function (li) {\n if (!li.subject) return true // skip non-group items (All groups, New group)\n return !!selectedGroups[li.subject.uri]\n })\n\n if (!allSelected) {\n allGroupsButton.classList.add('allGroupsButton--loading')\n allGroupsButton.setAttribute('aria-busy', 'true')\n selectAllGroups(selectedGroups, ulGroups, function (ok, message) {\n if (!ok) return alertDialog('Failed to select all groups. If it persists, contact admin.')\n allGroupsButton.classList.remove('allGroupsButton--loading')\n allGroupsButton.setAttribute('aria-busy', 'false')\n allGroupsButton.classList.add('allGroupsButton--active')\n refreshThingsSelected(ulGroups, selectedGroups)\n refreshNames(ctx.ulPeople, null)\n })\n } else {\n allGroupsButton.classList.remove('allGroupsButton--loading', 'allGroupsButton--active')\n allGroupsButton.setAttribute('aria-busy', 'false')\n allGroupsButton.classList.add('allGroupsButton--loaded') // pale green hint groups loaded\n for (const key in selectedGroups) delete selectedGroups[key]\n refreshThingsSelected(ulGroups, selectedGroups)\n }\n }) // on button click\n ctx.allGroupsLi.appendChild(allGroupsButton)\n ulGroups.appendChild(ctx.allGroupsLi) // First item in the list\n\n // New group button — rightmost (appended after group buttons are rendered)\n ctx.newGroupLi = dom.createElement('li')\n const newGroupButton = dom.createElement('button')\n newGroupButton.setAttribute('type', 'button')\n newGroupButton.innerHTML = '+ New group'\n newGroupButton.classList.add('allGroupsButton', 'actionButton', 'btn-secondary', 'action-button-focus')\n actionButtons.push(newGroupButton)\n newGroupButton.addEventListener(\n 'click', function (event) {\n setActiveGroupButton(ulGroups, newGroupButton)\n setActiveActionButton(null)\n deselectAllPeople(ctx.ulPeople)\n handleNewGroupClick(ctx)\n },\n false\n )\n ctx.newGroupLi.appendChild(newGroupButton)\n\n // Append ulGroups to buttonSection, then add New group at the end\n buttonSection.appendChild(ulGroups)\n\n if (groupIndex) {\n kb.fetcher.nowOrWhenFetched(groupIndex.uri, book, function (ok, body) {\n if (!ok) {\n debug.error('Error loading group index. Stack: ' + body)\n alertDialog('Error loading group index. If it persists, contact admin.')\n return\n }\n // Remove special items before sync (syncTableToArrayReOrdered expects .subject on all children)\n if (ctx.allGroupsLi.parentNode) ctx.allGroupsLi.parentNode.removeChild(ctx.allGroupsLi)\n if (ctx.newGroupLi.parentNode) ctx.newGroupLi.parentNode.removeChild(ctx.newGroupLi)\n syncGroupUl(book, options, ulGroups, dom, selectedGroups, ctx.ulPeople, ctx.searchInput) // Refresh list of groups\n ulGroups.insertBefore(ctx.allGroupsLi, ulGroups.firstChild) // Keep All contacts first\n ulGroups.appendChild(ctx.newGroupLi) // Keep New group last\n\n // Auto-select all groups and display all contacts on load\n allGroupsButton.classList.add('allGroupsButton--loading')\n allGroupsButton.setAttribute('aria-busy', 'true')\n selectAllGroups(selectedGroups, ulGroups, function (ok, message) {\n if (!ok) return alertDialog('Failed to select all groups. If it persists, contact admin.')\n allGroupsButton.classList.remove('allGroupsButton--loading')\n allGroupsButton.setAttribute('aria-busy', 'false')\n allGroupsButton.classList.add('allGroupsButton--active')\n refreshThingsSelected(ulGroups, selectedGroups)\n refreshNames(ctx.ulPeople, null)\n })\n })\n }\n\n // Remove special items before initial render too\n if (ctx.allGroupsLi.parentNode) ctx.allGroupsLi.parentNode.removeChild(ctx.allGroupsLi)\n if (ctx.newGroupLi.parentNode) ctx.newGroupLi.parentNode.removeChild(ctx.newGroupLi)\n renderGroupButtons(book, ulGroups, options, dom, selectedGroups, ctx.ulPeople, ctx.searchInput, ctx.detailsSectionContent, ctx.dataBrowserContext, function () {\n setActiveActionButton(null)\n // Keep the details section open when a contact or New contact form is showing\n if (!ctx.detailsSectionContent.querySelector('.contactTypeChooser, .contactFormContainer, .renderPane')) {\n ctx.detailsSectionContent.innerHTML = ''\n ctx.detailsSection.classList.add('hidden')\n }\n })\n ulGroups.insertBefore(ctx.allGroupsLi, ulGroups.firstChild) // Keep All contacts first\n ulGroups.appendChild(ctx.newGroupLi) // Ensure New group is last after initial render\n } else {\n syncGroupUl(book, options, ulGroups, dom, selectedGroups, ctx.ulPeople, ctx.searchInput) // Refresh list of groups (will be empty)\n refreshNames(ctx.ulPeople, null)\n debug.log('No book, only one group -> hide list of groups')\n } // if not book\n\n return { buttonSection, ulGroups }\n}\n\n// ── Builder: footer action buttons (Groups / Sharing / Tools) ────────\nfunction buildFooterButtons (ctx) {\n const {\n dom, kb, ns, book, options, selectedGroups,\n actionButtons, setActiveActionButton, dataBrowserContext, div, me\n } = ctx\n\n const cardFooter = dom.createElement('div')\n cardFooter.classList.add('cardFooter')\n\n if (book) {\n // Groups button\n const groupsButton = cardFooter.appendChild(dom.createElement('button'))\n groupsButton.setAttribute('type', 'button')\n groupsButton.innerHTML = 'Groups'\n groupsButton.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n actionButtons.push(groupsButton)\n groupsButton.addEventListener('click', async function (_event) {\n setActiveActionButton(groupsButton)\n deselectAllPeople(ctx.ulPeople)\n ctx.showDetailsSection()\n ctx.detailsSectionContent.innerHTML = ''\n ctx.detailsSectionContent.classList.remove('detailsSectionContent--wide')\n\n // Header\n const groupsHeader = dom.createElement('h3')\n groupsHeader.textContent = 'Your groups'\n ctx.detailsSectionContent.appendChild(groupsHeader)\n\n let groupRemark = dom.createElement('p')\n groupRemark.textContent = 'When you delete a group it can happen that some contacts end up groupless.'\n ctx.detailsSectionContent.appendChild(groupRemark)\n\n groupRemark = dom.createElement('p')\n groupRemark.textContent = 'To move contacts around, simply drag and drop them onto a group.'\n ctx.detailsSectionContent.appendChild(groupRemark)\n\n // Load all groups and display them in a list\n let groups\n try {\n groups = await loadAllGroups(book)\n } catch (err) {\n ctx.detailsSectionContent.appendChild(dom.createTextNode('Failed to load groups: ' + err))\n return\n }\n\n const groupsList = dom.createElement('ul')\n groupsList.setAttribute('role', 'list')\n groupsList.setAttribute('aria-label', 'All groups')\n groupsList.classList.add('groupButtonsList')\n\n // Sort groups by name\n if (groups) {\n groups.sort((a, b) => {\n const nameA = (kb.any(a, ns.vcard('fn')) || '').toString().toLowerCase()\n const nameB = (kb.any(b, ns.vcard('fn')) || '').toString().toLowerCase()\n return nameA < nameB ? -1 : nameA > nameB ? 1 : 0\n })\n groups.forEach(function (group) {\n const { groupLi, groupButton: groupBtn, name } = createGroupLi(group)\n groupBtn.addEventListener('click', function (event) {\n event.preventDefault()\n if (!event.metaKey) {\n for (const key in selectedGroups) delete selectedGroups[key]\n }\n selectedGroups[group.uri] = !selectedGroups[group.uri]\n refreshThingsSelected(ctx.ulGroups, selectedGroups)\n // Highlight the matching group button in the sidebar ulGroups\n const matchingLi = Array.from(ctx.ulGroups.children).find(li => li.subject && li.subject.uri === group.uri)\n setActiveGroupButton(ctx.ulGroups, matchingLi ? matchingLi.querySelector('button') : null)\n kb.fetcher.nowOrWhenFetched(group.doc(), undefined, function (ok, message) {\n if (!ok) {\n debug.error('Cannot load group: ' + group + '. Stack: ' + message)\n return alertDialog('Failed to load group details. If it persists, contact your admin.')\n }\n refreshNames(ctx.ulPeople, null, false)\n })\n }, false)\n UI.widgets.makeDropTarget(groupLi, uris => handleURIsDroppedOnGroup(uris, group))\n\n if (me) {\n UI.widgets.deleteButtonWithCheck(\n dom,\n groupLi,\n 'group ' + name,\n async function () {\n await deleteThingAndDoc(group)\n delete selectedGroups[group.uri]\n // Refresh the group buttons list\n const allGroupsLi = ctx.allGroupsLi\n const newGroupLi = ctx.newGroupLi\n if (allGroupsLi.parentNode) allGroupsLi.parentNode.removeChild(allGroupsLi)\n if (newGroupLi.parentNode) newGroupLi.parentNode.removeChild(newGroupLi)\n syncGroupUl(book, options, ctx.ulGroups, dom, selectedGroups, ctx.ulPeople, ctx.searchInput)\n ctx.ulGroups.insertBefore(allGroupsLi, ctx.ulGroups.firstChild)\n ctx.ulGroups.appendChild(newGroupLi)\n refreshThingsSelected(ctx.ulGroups, selectedGroups)\n // Refresh the people list to reflect the deleted group\n refreshNames(ctx.ulPeople, null, false)\n // Refresh the groups detail view\n groupsButton.click()\n }\n )\n }\n\n groupsList.appendChild(groupLi)\n })\n }\n\n ctx.detailsSectionContent.appendChild(groupsList)\n\n // New group button at the bottom\n const newGroupBtn = dom.createElement('button')\n newGroupBtn.setAttribute('type', 'button')\n newGroupBtn.innerHTML = '+ New group'\n newGroupBtn.classList.add('actionButton', 'btn-primary', 'action-button-focus', 'newGroupBtn')\n newGroupBtn.addEventListener('click', function () { handleNewGroupClick(ctx) }, false)\n ctx.detailsSectionContent.appendChild(newGroupBtn)\n })\n\n // Sharing button\n const sharingButton = cardFooter.appendChild(dom.createElement('button'))\n sharingButton.setAttribute('type', 'button')\n sharingButton.innerHTML = 'Sharing'\n sharingButton.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n actionButtons.push(sharingButton)\n sharingButton.addEventListener('click', function (_event) {\n setActiveActionButton(sharingButton)\n deselectAllPeople(ctx.ulPeople)\n ctx.showDetailsSection()\n ctx.detailsSectionContent.innerHTML = ''\n ctx.detailsSectionContent.classList.remove('detailsSectionContent--wide')\n\n const sharingHeader = dom.createElement('h3')\n sharingHeader.textContent = 'Sharing'\n ctx.detailsSectionContent.appendChild(sharingHeader)\n\n ctx.detailsSectionContent.appendChild(\n UI.aclControl.ACLControlBox5(\n book.dir(),\n dataBrowserContext,\n 'book',\n kb,\n function (ok, body) {\n if (!ok) {\n debug.error('ACL control box Failed. Stack: ' + body)\n complain(ctx.detailsSectionContent, dom, 'Problem displaying sharing controls. If persists, contact admin.')\n }\n }\n )\n )\n\n const sharingContext = {\n target: book,\n me,\n noun: 'address book',\n div: ctx.detailsSectionContent,\n dom,\n statusRegion: div\n }\n UI.login.registrationControl(sharingContext, book, ns.vcard('AddressBook'))\n .then(() => debug.log('Registration control finished.'))\n .catch(e => {\n debug.error('Error in registration control. Stack: ' + e)\n complain(ctx.detailsSectionContent, dom, 'Problem displaying findable controls. If persists, contact admin.')\n })\n })\n\n // Settings button\n const toolsButton = cardFooter.appendChild(dom.createElement('button'))\n toolsButton.setAttribute('type', 'button')\n toolsButton.innerHTML = 'Tools'\n toolsButton.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n actionButtons.push(toolsButton)\n toolsButton.addEventListener('click', function (_event) {\n setActiveActionButton(toolsButton)\n deselectAllPeople(ctx.ulPeople)\n ctx.showDetailsSection()\n ctx.detailsSectionContent.innerHTML = ''\n ctx.detailsSectionContent.classList.add('detailsSectionContent--wide')\n ctx.detailsSectionContent.appendChild(\n toolsPane(\n selectAllGroups,\n selectedGroups,\n ctx.ulGroups,\n book,\n dataBrowserContext,\n me,\n function refreshGroups () {\n if (ctx.allGroupsLi.parentNode) ctx.allGroupsLi.parentNode.removeChild(ctx.allGroupsLi)\n if (ctx.newGroupLi.parentNode) ctx.newGroupLi.parentNode.removeChild(ctx.newGroupLi)\n syncGroupUl(book, options, ctx.ulGroups, dom, selectedGroups, ctx.ulPeople, ctx.searchInput)\n ctx.ulGroups.insertBefore(ctx.allGroupsLi, ctx.ulGroups.firstChild)\n ctx.ulGroups.appendChild(ctx.newGroupLi)\n refreshThingsSelected(ctx.ulGroups, selectedGroups)\n }\n )\n )\n })\n } // if book\n\n return cardFooter\n}\n\nexport { saveNewGroup, addPersonToGroup, groupMembers, saveNewContact } from './contactLogic'\nexport { addWebIDToContacts, removeWebIDFromContacts, getPersonas } from './webidControl'\n"],"names":[],"sourceRoot":""}
1
+ {"version":3,"file":"contactsPane.js","mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,O;;;;;;;;;;;;;;;;ACVA;AAC6G;AACjB;AACO;AACnG,4CAA4C,kEAAka;AAC9c,8BAA8B,mFAA2B,CAAC,4FAAqC;AAC/F,yCAAyC,sFAA+B;AACxE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,eAAe;AACf,gBAAgB;AAChB;AACA;AACA;;AAEA;AACA;AACA,uBAAuB;AACvB;AACA,uBAAuB;AACvB;AACA;AACA;;AAEA;AACA,uBAAuB;AACvB;;AAEA;AACA;AACA,qBAAqB;AACrB,uBAAuB;AACvB;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,sBAAsB;AACtB;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,0BAA0B,mCAAmC;AAC7D;AACA,sCAAsC;AACtC,oCAAoC;AACpC;AACA,2CAA2C;AAC3C;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,qBAAqB;AACrB;AACA;AACA;AACA,eAAe;AACf;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,qBAAqB;AACrB;AACA,gBAAgB;AAChB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,6DAA6D;AAC7D;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;AAGA;AAC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qBAAqB,GAAG,oCAAoC,qBAAqB,eAAe,cAAc,gBAAgB,qBAAqB,qBAAqB,GAAG,oCAAoC,8EAA8E,+BAA+B,GAAG,wGAAwG,kBAAkB,wBAAwB,mCAAmC,GAAG,mCAAmC,+BAA+B,gCAAgC,mBAAmB,kBAAkB,wBAAwB,4BAA4B,GAAG,uDAAuD,8BAA8B,+BAA+B,kBAAkB,wBAAwB,4BAA4B,GAAG,uCAAuC,6BAA6B,8BAA8B,uBAAuB,sBAAsB,GAAG,iCAAiC,YAAY,mCAAmC,qBAAqB,GAAG,iCAAiC,sBAAsB,qCAAqC,wBAAwB,qBAAqB,4BAA4B,GAAG,kCAAkC,sBAAsB,kBAAkB,wBAAwB,GAAG,mCAAmC,iBAAiB,GAAG,mBAAmB;AAC7yrB;AACA,iEAAe,uBAAuB,EAAC;;;;;;;;;;;;;;;ACrnBvC;AAC6G;AACjB;AAC5F,8BAA8B,mFAA2B,CAAC,4FAAqC;AAC/F;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,OAAO,qGAAqG,MAAM,YAAY,aAAa,OAAO,aAAa,MAAM,YAAY,OAAO,YAAY,YAAY,OAAO,aAAa,MAAM,UAAU,MAAM,aAAa,MAAM,UAAU,YAAY,WAAW,MAAM,aAAa,cAAc,aAAa,MAAM,YAAY,OAAO,YAAY,MAAM,YAAY,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CA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV,iDAAiD,qBAAqB;AACtE;AACA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV,sDAAsD,qBAAqB;AAC3E;AACA;AACA;AACA;AACA;AACA;AACA;AACA,E;;;;;;;ACpFa;;AAEb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,E;;;;;;;ACzBa;;AAEb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uDAAuD,cAAc;AACrE;AACA;AACA;AACA;AACA,E;;;;;;;ACfa;;AAEb;AACA;AACA;AACA,kBAAkB,wBAAwB;AAC1C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB,iBAAiB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,4BAA4B;AAChD;AACA;AACA;AACA;AACA;AACA,qBAAqB,6BAA6B;AAClD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,E;;;;;;;ACnFa;;AAEb;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kC;;;;;;;ACjCa;;AAEb;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oC;;;;;;;ACTa;;AAEb;AACA;AACA,cAAc,KAAwC,GAAG,sBAAiB,GAAG,CAAI;AACjF;AACA;AACA;AACA;AACA,gD;;;;;;;A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;AACP;AACA;AACA;AACA;AACA;;AAEO;AACP;AACA,6BAA6B,WAAW;AACxC;AACA;AACA;AACA;AACA;;AAEO;AACP;AACA;AACA;AACA;AACA,MAAM,GAAS,mCAAmC,SAAS,KAAK,SAAS;AACzE;AACA;AACA;AACA,yBAAyB,cAAc;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO;AACP;AACA,6CAA6C;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,uEAAY;AACpC;AACA;AACA;AACA,UAAU;AACV,UAAU,KAAW,sBAAsB,OAAO,OAAO,OAAO,IAAI,IAAI;AACxE;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA,wCAAwC,sEAAK;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR,QAAQ,KAAW;AACnB;AACA;AACA;AACA,KAAK;AACL,MAAM,KAAW;AACjB;AACA;AACA,KAAK;AACL;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN,MAAM,KAAW;AACjB;AACA;AACA;AACA;;AAEA,UAAU,MAAM;AAChB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA,0BAA0B;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN,MAAM,KAAW;AACjB;AACA;AACA;AACA;AACA;;AAEA;AACA;;;;;;ACpUA,MAAkG;AAClG,MAAwF;AACxF,MAA+F;AAC/F,MAAkH;AAClH,MAA2G;AAC3G,MAA2G;AAC3G,MAA2G;AAC3G;AACA;;AAEA,IAAI,kBAAO;;AAEX,kBAAO,qBAAqB,6BAAmB;AAC/C,kBAAO,iBAAiB,0CAAa;AACrC,kBAAO,UAAU,+BAAa;AAC9B,kBAAO,UAAU,uBAAM;AACvB,kBAAO,sBAAsB,8BAAkB;;AAE/C,IAAI,iBAAM,GAAG,kCAAG,CAAC,yBAAO,EAAE,kBAAO;;;;AAI4C;AAC7E,OAAO,wDAAe,yBAAO,IAAI,yBAAO,UAAU,yBAAO,mBAAmB,EAAC;;;ACxB7C;AACF;AACK;AACH;;AAEhC,MAAM,aAAE,GAAG,0FAAK;AAChB,MAAM,aAAE,GAAG,sEAAK;AAChB;;AAEO;AACP;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA,sBAAsB,yBAAyB;AAC/C;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,KAAK;AACL;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;AACA;AACA,gBAAgB,yCAAyC;AACzD,GAAG;AACH;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;AACA;AACA;AACA,QAAQ,6CAA6C;AACrD,QAAQ;AACR;AACA,GAAG;AACH;;AAEA;;AAEA;AACA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA;AACA;AACA;;AAEO;AACP,kBAAkB,2EAAU;AAC5B;;AAEO,SAAS,oBAAS;AACzB,uBAAuB,aAAE;AACzB,kBAAkB,aAAE;AACpB;AACA;AACA;AACO;AACP;AACA;AACA,uCAAuC,aAAE;AACzC,2BAA2B,aAAE,cAAc,aAAE;AAC7C;AACA,UAAU;AACV,UAAU,GAAS;AACnB;AACA;AACA,OAAO;AACP,MAAM,GAAS;AACf;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA,EAAE,GAAS;AACX,aAAa,aAAE,8BAA8B,aAAE;AAC/C;AACA,UAAU,aAAE;AACZ,UAAU,aAAE;AACZ,IAAI,GAAS;AACb,IAAI;AACJ,IAAI,KAAW;AACf;AACA;AACA;;AAEO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO;AACP;AACA,IAAI,aAAE,QAAQ,aAAE;AAChB,IAAI,aAAE,QAAQ,aAAE;AAChB,IAAI,aAAE,QAAQ,aAAE;AAChB;AACA;;AAEA;AACA;AACA,WAAW,aAAa;AACxB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEO;AACP,YAAY,aAAE;AACd,aAAa,aAAE;AACf;;AAEA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;;ACnW8B;AACA;AACK;AA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CnB;AACS;AACP;;AAEhC,QAAQ,mBAAmB,EAAE,wGAAmB;AAChD;AACA;AACA;;AAEA;AACA;;AAEA;;AAEO;AACP;AACA,IAAI,yEAAQ;AACZ;AACA;AACA,QAAQ,GAAS;AACjB;;AAEA;AACA;AACA;AACA,mBAAmB,sEAAK;AACxB;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,4BAA4B;AACxD;AACA;AACA,aAAa;AACb;AACA,cAAc,KAAW;AACzB;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX,YAAY,2DAA2D;AACvE,YAAY,2DAA2D;AACvE,YAAY,sCAAsC;AAClD;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,UAAU,GAAS,QAAQ,iBAAiB,aAAa,eAAe;AACxE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,6BAA6B;AAC3C;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,gBAAgB,KAAW;AAC3B;AACA;AACA;AACA;AACA;AACA,eAAe;AACf;;AAEA;AACA;AACA,YAAY;AACZ;AACA,YAAY,GAAS;AACrB,uBAAuB,mEAAQ;AAC/B,mDAAmD;;AAEnD;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA,cAAc;AACd;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA,QAAQ,IAAU;AAClB,QAAQ,QAAQ;AAChB;AACA;AACA,GAAG;AACH;;;;;;ACvKA,MAAkG;AAClG,MAAwF;AACxF,MAA+F;AAC/F,MAAkH;AAClH,MAA2G;AAC3G,MAA2G;AAC3G,MAA+G;AAC/G;AACA;;AAEA,IAAI,sBAAO;;AAEX,sBAAO,qBAAqB,6BAAmB;AAC/C,sBAAO,iBAAiB,0CAAa;AACrC,sBAAO,UAAU,+BAAa;AAC9B,sBAAO,UAAU,uBAAM;AACvB,sBAAO,sBAAsB,8BAAkB;;AAE/C,IAAI,qBAAM,GAAG,kCAAG,CAAC,6BAAO,EAAE,sBAAO;;;;AAIgD;AACjF,OAAO,4DAAe,6BAAO,IAAI,6BAAO,UAAU,6BAAO,mBAAmB,EAAC;;;ACxB/C;AACK;AACL;AACM;AACJ;AACyB;;AAEzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,MAAM,iBAAE,GAAG,sEAAK;AAChB,MAAM,oBAAK,GAAG,yEAAQ;AACtB,MAAM,iBAAE,GAAG,0FAAK;;AAEhB;AACA;AACA;AACA;AACA;AACO;AACP;AACA,2BAA2B,2EAAU;AACrC;;AAEA;AACA;AACA,MAAM,kEAAO,UAAU,iBAAE;AACzB;AACA;AACA;AACA,cAAc,iBAAE;AAChB,QAAQ;AACR,cAAc,iBAAE;AAChB;AACA,MAAM;AACN;AACA,MAAM,KAAW;AACjB;AACA;AACA;;AAEA;AACA,IAAI,iBAAE;AACN;AACA,QAAQ,KAAW;AACnB,QAAQ;AACR,sBAAsB,iBAAE;AACxB;AACA,UAAU,GAAS;AACnB;AACA,QAAQ,GAAS;AACjB,QAAQ,iBAAE,cAAc,iBAAE;AAC1B;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAM,IAAU;AAChB;AACA;AACA;AACA;AACA;AACA,kBAAkB,iBAAE;AACpB,MAAM;AACN;AACA,kBAAkB,iBAAE;AACpB;;AAEA;AACA,kBAAkB;AAClB;AACA,YAAY,iBAAE;AACd,WAAW,iBAAE,gBAAgB,iBAAE;AAC/B;AACA;AACA;AACA;AACA,IAAI,GAAS;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,iBAAE;AACN;AACA;AACA;AACA,OAAO;AACP;AACA;AACA,UAAU,KAAW;AACrB;AACA;AACA;AACA,QAAQ,GAAS;AACjB,QAAQ,iBAAE;AACV,QAAQ,iBAAE;AACV,oCAAoC,4BAA4B;AAChE;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA,cAAc,KAAW;AACzB;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA,kBAAkB,mEAAQ;AAC1B,MAAM,GAAS;AACf;AACA;AACA;AACA,qCAAqC;AACrC,kBAAkB,mEAAQ;AAC1B;AACA,0BAA0B;AAC1B;AACA;AACA,yBAAyB,iBAAE;AAC3B,UAAU;AACV,UAAU,KAAW;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,KAAW;AACrB;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,oBAAoB,kBAAkB;AACtC;AACA,MAAM,GAAS;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,UAAU,GAAS;AACnB;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI,2EAAU;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,0FAAK;AACX;AACA;AACA,SAAS;AACT;AACA;AACA;AACA,SAAS;AACT,MAAM,2EAAU;AAChB;AACA;AACA;;AAEA;AACA,iBAAiB,iBAAE,eAAe,iBAAE;AACpC;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR,MAAM;AACN,MAAM,oBAAK;AACX;AACA;;AAEA;AACA;AACA,qBAAqB,iBAAE;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,mBAAmB,2EAAU;AAC7B;AACA,MAAM,yEAAQ;AACd;AACA;AACA,QAAQ;AACR;AACA;AACA,qBAAqB,iBAAE;AACvB,uBAAuB,iBAAE;AACzB;AACA;AACA;AACA,UAAU,WAAW;AACrB;AACA;AACA,kBAAkB,aAAa;AAC/B;AACA,YAAY,GAAS;AACrB,yCAAyC,iBAAE;AAC3C,YAAY,GAAS;AACrB,kBAAkB,iBAAE;AACpB,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,2EAAU;AACd;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,MAAM,yEAAQ,mBAAmB,iBAAE;AACnC;AACA;AACA;AACA,QAAQ,2EAAU;AAClB;AACA,MAAM;AACN,MAAM,GAAS;AACf;AACA;AACA;AACA;;AAEA;;AAEA,mBAAmB,iBAAE,qCAAqC,iBAAE;AAC5D;AACA;AACA;AACA,EAAE,2EAAU;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;AC7UA,MAAkG;AAClG,MAAwF;AACxF,MAA+F;AAC/F,MAAkH;AAClH,MAA2G;AAC3G,MAA2G;AAC3G,MAAgH;AAChH;AACA;;AAEA,IAAI,uBAAO;;AAEX,uBAAO,qBAAqB,6BAAmB;AAC/C,uBAAO,iBAAiB,0CAAa;AACrC,uBAAO,UAAU,+BAAa;AAC9B,uBAAO,UAAU,uBAAM;AACvB,uBAAO,sBAAsB,8BAAkB;;AAE/C,IAAI,sBAAM,GAAG,kCAAG,CAAC,8BAAO,EAAE,uBAAO;;;;AAIiD;AAClF,OAAO,6DAAe,8BAAO,IAAI,8BAAO,UAAU,8BAAO,mBAAmB,EAAC;;;ACxBM;AACrD;AACY;AACV;AAC4F;AAClE;;AAE1D,MAAM,uBAAE,GAAG,sEAAK;AAChB,MAAM,0BAAK,GAAG,yEAAQ;AACtB,MAAM,uBAAE,GAAG,0FAAK;AAChB,IAAI,wBAAG;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEO;AACP;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEO;AACP,EAAE,wBAAG;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,0BAAK;AACP;;AAEA;AACA,aAAa,6BAA6B;AAC1C;AACO;AACP,eAAe,uBAAE,YAAY,uBAAE;AAC/B,kBAAkB,wBAAG;AACrB;AACA;AACA;AACA,EAAE,2EAAU;;AAEZ,0CAA0C,wBAAG;AAC7C;AACA;AACA;;AAEA,WAAW;AACX;;AAEO;AACP;AACA,gBAAgB,uBAAE;AAClB;AACA,oBAAoB,gBAAgB;AACpC,MAAM;AACN;AACA,MAAM,WAAW;AACjB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,uBAAE;AACN;AACA,QAAQ,KAAW;AACnB;AACA;AACA,KAAK;AACL;;AAEA,UAAU,uBAAuB;;AAEjC;AACA,EAAE,2EAAU;AACZ;AACA;AACA,EAAE;;AAEK;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,uBAAE;AACR;AACA;AACA;AACA;AACA;AACA,UAAU,KAAW;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL;;AAEA,kBAAkB,8BAA8B;AAChD;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,IAAI;AACJ;;AAEO;AACP,kBAAkB,wBAAwB;AAC1C;AACA;AACA;AACA;AACA;AACA;;AAEO;AACP,EAAE,wBAAG;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,0BAAK;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAM,uBAAE,2BAA2B,uBAAE;AACrC;AACA;AACA;AACA;AACA,uBAAuB,uBAAE,WAAW,uBAAE;AACtC,sBAAsB,uBAAE,YAAY,uBAAE;AACtC;AACA,oBAAoB,uBAAE,QAAQ,uBAAE;AAChC,KAAK;AACL;AACA;AACA;AACA;AACA;;AAEO;AACP,qBAAqB,uBAAE,WAAW,uBAAE;AACpC;AACA,UAAU,uBAAE;AACZ,sBAAsB,uBAAE,YAAY,uBAAE;AACtC,UAAU,uBAAE;AACZ;AACA,IAAI;AACJ;AACA;AACA;;AAEA;AACO;AACP;AACA;AACA;AACA;AACA;AACA,QAAQ,uBAAE;AACV,cAAc,uBAAE,gBAAgB,uBAAE;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI,IAAU;AACd;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA,6DAA6D,uBAAE;AAC/D;AACA;AACA,2BAA2B,YAAY,CAAC,uBAAE;AAC1C;AACA,GAAG;AACH,aAAa,cAAc;AAC3B,kBAAkB,qBAAqB;AACvC;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA,qBAAqB,wBAAG;AACxB;AACA;AACA;AACA;AACA,IAAI,2EAAU;;AAEd;AACA,mBAAmB,wBAAG;AACtB;;AAEA;AACA,sBAAsB,wBAAG;AACzB;AACA;AACA,0BAA0B,wBAAG;AAC7B;AACA;AACA;;AAEA;AACA,iBAAiB,OAAO;;AAExB;AACA;AACA,wBAAwB,uBAAE,aAAa,uBAAE;AACzC;AACA,oBAAoB,wBAAG;AACvB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,IAAI,uBAAE;AACN;AACA,QAAQ,KAAW;AACnB;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA,oBAAoB,wBAAG;AACvB;;AAEA;AACA,oBAAoB,wBAAG;AACvB;AACA;;AAEA;;AAEA;AACA,qBAAqB,wBAAG;AACxB;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,EAAE,0BAAK;AACP;AACA,EAAE;;AAEK;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA,IAAI,QAAQ,cAAc,wBAAG;AAC7B;AACA;AACA,EAAE,uBAAE;AACJ;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,KAAW;AACjB,MAAM,QAAQ,cAAc,wBAAG;AAC/B;AACA;AACA;;AAEA;AACA,oBAAoB,wBAAG;AACvB;AACA,mBAAmB,2EAAU,UAAU,wBAAG;AAC1C;AACA;;AAEA,QAAQ,0FAAK;AACb;AACA,2BAA2B,2EAAU;AACrC,QAAQ,wBAAG;AACX;AACA;AACA;AACA;;AAEA,wBAAwB,uBAAE,aAAa,uBAAE;AACzC,UAAU,GAAS;AACnB;AACA;AACA,iCAAiC,uBAAE,WAAW,uBAAE;AAChD,gBAAgB,uBAAE;;AAElB;AACA;AACA;;AAEA;AACA,yBAAyB,sCAAe;AACxC;AACA;AACA;AACA,2BAA2B,oBAAS,CAAC,uBAAE;AACvC;AACA;AACA,kBAAkB,oBAAS,CAAC,uBAAE;AAC9B,2DAA2D,uBAAE,2BAA2B,uBAAE;AAC1F;AACA,aAAa;AACb,WAAW;;AAEX;AACA,gBAAgB,uBAAE;;AAElB;AACA,kBAAkB,iBAAiB;AACnC,YAAY;AACZ,YAAY,QAAQ,cAAc,wBAAG;AACrC;AACA;;AAEA;AACA,kBAAkB,eAAe,CAAC,uBAAE,sBAAsB,wBAAG;AAC7D,YAAY;AACZ;AACA,YAAY,QAAQ,cAAc,wBAAG;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;AACH;;AAEO;AACP;AACA;AACA,oBAAoB,8BAA8B;AAClD;AACA;AACA;AACA;;AAEO;AACP;AACA;AACA,kBAAkB,8BAA8B;AAChD;AACA,+BAA+B,OAAO;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,kBAAkB,kBAAkB;AACpC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,kBAAkB,uBAAE;AACpB;AACA,kBAAkB,oBAAoB;AACtC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACO;AACP;AACA;;AAEA;AACA,YAAY,WAAW,QAAQ,kBAAkB;;AAEjD,QAAQ,0FAAK;AACb;AACA,QAAQ,2EAAU;AAClB,UAAU,wBAAG;AACb;AACA;AACA;AACA,kBAAkB,uBAAE;AACpB,YAAY,GAAS;AACrB,WAAW;AACX;AACA;AACA;AACA;;AAEA;AACO;AACP;AACA;AACA,UAAU,uBAAE;AACZ,IAAI;AACJ;AACA;AACA,yBAAyB,uBAAE,cAAc,uBAAE;AAC3C;AACA,QAAQ,uBAAE;AACV;;;AC7hBA;AAC8B;AACY;AACL;AACL;AAC4C;AACvB;AACT;;AAE5C,MAAM,yBAAE,GAAG,sEAAK;AAChB,MAAM,yBAAE,GAAG,0FAAK;;AAEhB;AACO,SAAS,sCAAe,kBAAkB,yBAAE;AACnD,8CAA8C,yBAAE;AAChD,6BAA6B,yBAAE;AAC/B,8CAA8C,iBAAiB;AAC/D;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,sDAAsD;AACtD;AACA;;AAEA;AACA;AACA,iCAAiC,yBAAE;AACnC,gCAAgC,yBAAE;AAClC;AACA,sCAAsC,yBAAE;AACxC;AACA;AACA;AACA,uCAAuC,yBAAE;AACzC,KAAK;AACL,aAAa,WAAW;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAkC,yBAAE;AACpC;AACA;AACA,MAAM,WAAW;AACjB;AACA;AACA;AACA;AACA;AACA,cAAc,aAAa;AAC3B;AACA;AACA;AACA;AACA,yCAAyC,yBAAE;AAC3C;AACA;AACA,OAAO;AACP;AACA;AACA,QAAQ;AACR;AACA,8BAA8B,2EAAU;AACxC;AACA;AACA,MAAM,GAAS;AACf;AACA;AACA;AACA;AACA;AACA,MAAM,YAAY;AAClB;AACA;;AAEA;AACA,gCAAgC,yBAAE;AAClC;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,mBAAmB,2EAAU;AAC7B;AACA;;AAEA,QAAQ,0FAAK;AACb;AACA,MAAM,2EAAU;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,uBAAuB,sCAAe;;AAEtC;AACA;AACA,MAAM;AACN;AACA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA,+BAA+B,yBAAE;AACjC;AACA;AACA;AACA;AACA,oCAAoC,yBAAE;AACtC,oCAAoC,yBAAE;AACtC;AACA;AACA;;AAEA,UAAU,MAAM;AAChB;;AAEA;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ACA,EAAE,cAAI;AACN,EAAE,wBAAc;AAChB;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;;AAErB,iBAAiB,cAAI;AACrB,2BAA2B,YAAE,KAAK,cAAI,EAAE,YAAE;AAC1C,IAAI,aAAG;;AAEP,IAAI,0FAAK;AACT;AACA;AACA;AACA,QAAQ,aAAG;;AAEX;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA,oBAAoB;AACpB;AACA;AACA,iBAAiB;AACjB;AACA;AACA,WAAW;AACX,UAAU;AACV;AACA;AACA,2BAA2B,YAAE,KAAK,cAAI;AACtC,4BAA4B,YAAE,KAAK,cAAI;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8BAA8B,uBAAuB;AACrD;AACA,gCAAgC,wBAAwB;AACxD,gEAAgE;AAChE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,WAAW;AACX,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,YAAY,YAAE;AACd;AACA;AACA,gBAAgB,aAAG;AACnB;AACA,wBAAwB,YAAE;AAC1B,wBAAwB,YAAE;AAC1B,wBAAwB,YAAE;AAC1B;AACA,yBAAyB,YAAE;AAC3B;AACA;AACA;AACA,qBAAqB;AACrB;;AAEA;AACA;AACA;AACA;AACA,kBAAkB,aAAG;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC,0EAAe,CAAC,YAAE;AACvD;AACA;AACA;AACA;AACA,kBAAkB,aAAG;AACrB;AACA,qCAAqC,YAAE,YAAY,YAAE;AACrD,sCAAsC,YAAE,YAAY,YAAE;AACtD,kCAAkC,uBAAuB;AACzD;AACA,oCAAoC,wBAAwB;AAC5D;AACA;AACA;AACA,sBAAsB,aAAG;AACzB,sBAAsB,aAAG;AACzB,sBAAsB,aAAG;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB,GAAS;AAC3B,kBAAkB;AAClB,kBAAkB,aAAG;AACrB,kBAAkB,aAAG;AACrB,kBAAkB,aAAG;AACrB,kBAAkB,aAAG;AACrB;AACA;AACA;AACA;AACA,eAAe;AACf;AACA,gBAAgB,aAAG;AACnB;AACA;AACA,eAAe;AACf,WAAW;AACX,UAAU;;AAEV;AACA;AACA;AACA,UAAU,aAAG;AACb;AACA;AACA;AACA,cAAc,aAAG;AACjB,cAAc,aAAG;AACjB;AACA;AACA;AACA;AACA,sCAAsC,2EAAU;AAChD;AACA,kCAAkC,kCAAkC;AACpE;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA,gBAAgB;AAChB;AACA;AACA;AACA;AACA;AACA,cAAc,aAAG;AACjB;AACA,aAAa;AACb,WAAW;AACX;;AAEA;AACA;AACA;AACA,YAAY,aAAG;AACf,4BAA4B,0BAA0B;AACtD;AACA;AACA;AACA,YAAY,YAAE,YAAY,YAAE;AAC5B,kCAAkC,+CAA+C,YAAY,CAAC,YAAE,WAAW;AAC3G,YAAY,aAAG;AACf;AACA,4BAA4B,+BAA+B;AAC3D;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,aAAG;;AAEf;AACA;AACA;AACA;AACA,8BAA8B,+BAA+B;AAC7D;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA,oBAAoB;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX,UAAU;;AAEV;AACA;AACA,0BAA0B,YAAE;AAC5B,YAAY,aAAG;;AAEf;AACA,wBAAwB,wBAAwB;AAChD;AACA,qBAAqB,YAAE,gBAAgB,YAAE;AACzC;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB;AACA;AACA;;AAEA;AACA,4BAA4B,6BAA6B;AACzD;AACA;AACA;AACA,4BAA4B,2BAA2B;AACvD;AACA;AACA;AACA;AACA,4BAA4B,wBAAwB;AACpD;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,aAAG;;AAEf,YAAY,aAAG;AACf,YAAY,aAAG;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;;AAEA;AACA;AACA;;AAEA;AACA;AACA,4BAA4B,YAAE;AAC9B;AACA,8BAA8B,0BAA0B;AACxD;AACA,kBAAkB,YAAE;AACpB;AACA;AACA,6BAA6B,0EAAe,CAAC,YAAE;AAC/C,cAAc,aAAG;AACjB;;AAEA,qBAAqB,YAAE;AACvB;AACA;AACA,eAAe;AACf,aAAa;AACb;AACA,cAAc,aAAG;AACjB;AACA,aAAa;AACb;AACA,cAAc,aAAG;AACjB,aAAa;AACb;;AAEA;AACA;;AAEA;AACA;AACA;AACA,2BAA2B,YAAE;AAC7B;AACA,8BAA8B,0BAA0B;AACxD;AACA,kBAAkB,YAAE;AACpB;AACA;AACA,6BAA6B,0EAAe,CAAC,YAAE;AAC/C,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,gCAAgC,iBAAiB;AACjD,8BAA8B,mBAAmB;AACjD,+BAA+B,gBAAgB;AAC/C;AACA;AACA;AACA;AACA;AACA,sBAAsB,QAAQ;AAC9B;AACA;;AAEA;AACA,gBAAgB,2CAA2C;AAC3D;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,qEAAqE;AACrE;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,gBAAgB,6BAA6B;AAC7C;AACA;;AAEA;AACA,gBAAgB,0BAA0B;AAC1C;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA,QAAQ,cAAc,2CAA2C,GAAS,gCAAgC;AAC1G;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,8CAA8C,sEAAK;AACnD;AACA;AACA;AACA;;AAEA;AACA,MAAM;AACN,IAAI;AACJ,CAAC,GAAC;;AAEF;AACA;AACA,UAAU,iEAAiE;AAC3E;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ,IAAI,GAAS;AACb;AACA,EAAE,GAAS;;AAEX,qBAAqB,2EAAU;AAC/B,wCAAwC,sEAAK;AAC7C;AACA;AACA;AACA,kBAAkB,YAAY;AAC9B,IAAI;AACJ,IAAI,GAAS;AACb;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,EAAE,WAAW;AACb;AACA;AACA,EAAE,qBAAqB;AACvB;AACA;AACA,EAAE,oBAAoB;AACtB,EAAE,YAAY;;AAEd;AACA,wCAAwC,8EAAa;AACrD;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA,UAAU,oDAAoD;AAC9D;AACA,EAAE,2EAAU;AACZ,qCAAqC,sEAAK;AAC1C;AACA;AACA;AACA;AACA;AACA,uBAAuB,cAAc;AACrC,QAAQ;AACR;AACA,QAAQ,WAAW;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,YAAY;AAClB;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA,UAAU,MAAM;AAChB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,WAAW;AACX;;AAEA;AACA;AACA,UAAU,mDAAmD;;AAE7D;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,EAAE,0FAAK;AACP;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,iBAAiB;AACrB;AACA;AACA;AACA;AACA,UAAU,gBAAgB;AAC1B;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU,MAAM;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI,qBAAqB;AACzB,GAAG;;AAEH;AACA;AACA;AACA;AACA,IAAI,qBAAqB;AACzB,GAAG;;AAEH,WAAW;AACX;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,oBAAoB;AAC1B;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA,QAAQ,eAAe;AACvB,0BAA0B,WAAW;AACrC;AACA;AACA;AACA,UAAU,qBAAqB;AAC/B,UAAU,YAAY;AACtB,SAAS;AACT,QAAQ;AACR;AACA;AACA;AACA;AACA,QAAQ,qBAAqB;AAC7B;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,oBAAoB;AAC5B;AACA,QAAQ,iBAAiB;AACzB;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,UAAU,KAAW;AACrB,UAAU,WAAW;AACrB;AACA;AACA;AACA;AACA;AACA,QAAQ,WAAW;AACnB;AACA;;AAEA;AACA;AACA;AACA,QAAQ,eAAe;AACvB,0BAA0B,WAAW;AACrC;AACA;AACA;AACA,UAAU,qBAAqB;AAC/B,UAAU,YAAY;AACtB,SAAS;AACT,OAAO;AACP;;AAEA;AACA;AACA;AACA,IAAI,kBAAkB;AACtB;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,IAAI;AACJ,IAAI,WAAW;AACf,IAAI,YAAY;AAChB,IAAI,GAAS;AACb,IAAI;;AAEJ,WAAW;AACX;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,iBAAiB;AACvB;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,uBAAuB,aAAa;AACpC,QAAQ;AACR;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,kBAAkB,uCAAuC,EAAE,aAAa;AACxE;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,qBAAqB;AACjC;AACA;AACA,YAAY,oBAAoB;AAChC;AACA;AACA,gBAAgB,KAAW;AAC3B,uBAAuB,WAAW;AAClC;AACA,cAAc,YAAY;AAC1B,aAAa;AACb,WAAW;AACX,UAAU,2EAAU,iCAAiC,wBAAwB;;AAE7E;AACA,YAAY,2EAAU;AACtB;AACA;AACA;AACA;AACA,sBAAsB,iBAAiB;AACvC;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,WAAW;AAC3B;AACA;AACA,gBAAgB,qBAAqB;AACrC;AACA,gBAAgB,YAAY;AAC5B;AACA;AACA;AACA;AACA;;AAEA;AACA,SAAS;AACT;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,0DAA0D,0BAA0B;AACpF;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,iBAAiB;AACvB;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,QAAQ,8EAAa;AACrB;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,KAAW;AACzB,cAAc,QAAQ;AACtB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,yEAAQ;AACd,oBAAoB,GAAS;AAC7B;AACA,UAAU,KAAW;AACrB,UAAU,QAAQ;AAClB,SAAS;AACT,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,iBAAiB;AACvB;AACA;AACA;AACA;AACA,QAAQ,mBAAS;AACjB,UAAU,eAAe;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,WAAW;AACvB;AACA;AACA,YAAY,qBAAqB;AACjC;AACA;AACA;AACA,KAAK;AACL,IAAI;;AAEJ;AACA;;AAE6F;AACJ","sources":["webpack://ContactsPane/webpack/universalModuleDefinition","webpack://ContactsPane/./src/styles/contactsPane.css","webpack://ContactsPane/./src/styles/contactsRDFFormsEnforced.css","webpack://ContactsPane/./src/styles/groupMembership.css","webpack://ContactsPane/./src/styles/individual.css","webpack://ContactsPane/./src/styles/localUtils.css","webpack://ContactsPane/./src/styles/mugshotGallery.css","webpack://ContactsPane/./src/styles/toolsPane.css","webpack://ContactsPane/./src/styles/utilities.css","webpack://ContactsPane/./src/styles/webidControl.css","webpack://ContactsPane/./node_modules/css-loader/dist/runtime/api.js","webpack://ContactsPane/./node_modules/css-loader/dist/runtime/getUrl.js","webpack://ContactsPane/./node_modules/css-loader/dist/runtime/sourceMaps.js","webpack://ContactsPane/./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js","webpack://ContactsPane/./node_modules/style-loader/dist/runtime/insertBySelector.js","webpack://ContactsPane/./node_modules/style-loader/dist/runtime/insertStyleElement.js","webpack://ContactsPane/./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js","webpack://ContactsPane/./node_modules/style-loader/dist/runtime/styleDomAPI.js","webpack://ContactsPane/./node_modules/style-loader/dist/runtime/styleTagTransform.js","webpack://ContactsPane/external umd {\"commonjs\":\"rdflib\",\"commonjs2\":\"rdflib\",\"amd\":\"rdflib\",\"root\":\"$rdf\"}","webpack://ContactsPane/external umd {\"commonjs\":\"solid-logic\",\"commonjs2\":\"solid-logic\",\"amd\":\"solid-logic\",\"root\":\"SolidLogic\"}","webpack://ContactsPane/external umd {\"commonjs\":\"solid-ui\",\"commonjs2\":\"solid-ui\",\"amd\":\"solid-ui\",\"root\":\"UI\"}","webpack://ContactsPane/webpack/bootstrap","webpack://ContactsPane/webpack/runtime/compat get default export","webpack://ContactsPane/webpack/runtime/define property getters","webpack://ContactsPane/webpack/runtime/hasOwnProperty shorthand","webpack://ContactsPane/webpack/runtime/jsonp chunk loading","webpack://ContactsPane/webpack/runtime/nonce","webpack://ContactsPane/./src/styles/webidControl.css?e193","webpack://ContactsPane/./src/debug.js","webpack://ContactsPane/./src/webidControl.js","webpack://ContactsPane/./src/styles/localUtils.css?6e73","webpack://ContactsPane/./src/localUtils.js","webpack://ContactsPane/./src/contactLogic.js","webpack://ContactsPane/./src/mintNewAddressBook.js","webpack://ContactsPane/./src/styles/mugshotGallery.css?feaa","webpack://ContactsPane/./src/mugshotGallery.js","webpack://ContactsPane/./src/styles/groupMembership.css?2a89","webpack://ContactsPane/./src/addressBookPresenter.js","webpack://ContactsPane/./src/groupMembershipControl.js","webpack://ContactsPane/./src/styles/individual.css?c2a6","webpack://ContactsPane/./src/styles/contactsRDFFormsEnforced.css?250c","webpack://ContactsPane/./src/rdfFormsHelper.js","webpack://ContactsPane/./src/individual.js","webpack://ContactsPane/./src/styles/toolsPane.css?78a3","webpack://ContactsPane/./src/toolsPane.js","webpack://ContactsPane/./src/styles/utilities.css?4cc3","webpack://ContactsPane/./src/styles/contactsPane.css?c6fd","webpack://ContactsPane/./src/contactsPane.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"solid-logic\"), require(\"solid-ui\"), require(\"rdflib\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"solid-logic\", \"solid-ui\", \"rdflib\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ContactsPane\"] = factory(require(\"solid-logic\"), require(\"solid-ui\"), require(\"rdflib\"));\n\telse\n\t\troot[\"ContactsPane\"] = factory(root[\"SolidLogic\"], root[\"UI\"], root[\"$rdf\"]);\n})(globalThis, (__WEBPACK_EXTERNAL_MODULE__941__, __WEBPACK_EXTERNAL_MODULE__104__, __WEBPACK_EXTERNAL_MODULE__53__) => {\nreturn ","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nimport ___CSS_LOADER_GET_URL_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/getUrl.js\";\nvar ___CSS_LOADER_URL_IMPORT_0___ = new URL(\"data:image/svg+xml,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 fill=%27%23999%27 viewBox=%270 0 24 24%27 width=%2720%27 height=%2720%27%3E%3Cpath d=%27M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99c.41.41 1.09.41 1.5 0s.41-1.09 0-1.5l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z%27/%3E%3C/svg%3E\", import.meta.url);\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\nvar ___CSS_LOADER_URL_REPLACEMENT_0___ = ___CSS_LOADER_GET_URL_IMPORT___(___CSS_LOADER_URL_IMPORT_0___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* Focus indicator for keyboard navigation */\n.contactPane table tr[tabindex=\"0\"]:focus {\n outline: var(--focus-ring-width) solid var(--color-primary);\n outline-offset: 2px;\n background: var(--color-info-bg);\n}\n/* contactsPane styles — extracted from inline styles in contactsPane.js */\n/* Uses CSS custom properties from the global stylesheet (dev-global.css / mashlib) */\n\n/* ── Layout: Three-column browser ────────────────────────────── */\n\n.contactPane .peopleSection .selected {\n background-color: var(--color-info-bg) !important;\n}\n\n.contactPane .detailSection,\n.contactPane .addressBookSection {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n flex: 1 1 0; /* allow it to grow but not force wrap */\n min-width: 0; /* allow sections to collapse when stacked */\n box-sizing: border-box;\n background: var(--color-section-bg);\n}\n\n.contactPane .detailsSectionContent {\n flex: 1 1 auto;\n min-height: 12.5rem; /* 200px */\n padding: var(--spacing-lg);\n max-width: 56.25rem; /* 900px */\n width: 100%;\n box-sizing: border-box;\n}\n\n.contactPane .detailsSectionContent--wide {\n max-width: 56.25rem; /* 900px */\n}\n\n.contactPane .cardFooter {\n display: flex;\n flex-wrap: nowrap; /* keep buttons inline */\n align-items: center; /* vertical centering if varied heights */\n gap: var(--spacing-xs);\n padding-top: var(--spacing-md);\n margin-top: var(--spacing-md);\n}\n\n.contactPane .detailsSectionContent {\n margin: 0;\n}\n\n/* ── Contact type chooser ───────────────────────────────────── */\n\n.contactPane .contactTypeChooser {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-sm);\n max-width: 22.5rem; /* 360px */\n}\n\n.contactPane .contactTypeChooser h3 {\n margin: 0 0 var(--spacing-xs) 0;\n font-size: var(--font-size-lg);\n}\n\n.contactPane .contactTypeSelect {\n height: var(--min-touch-target);\n border: var(--border-width-sm, 1px) solid var(--color-border-pale);\n border-radius: var(--border-radius-base);\n padding: 0 var(--spacing-sm);\n font-size: var(--font-size-sm);\n background: var(--color-section-bg);\n}\n\n/* ── Search ──────────────────────────────────────────────────── */\n\n.contactPane .allGroupsButton {\n border-radius: var(--border-radius-full) !important;\n /* existing styles */\n}\n/* wrapper to position clear icon/button */\n.contactPane .searchDiv {\n position: relative;\n}\n\n.contactPane .searchInput {\n height: var(--min-touch-target);\n border: var(--border-width-sm, 1px) solid var(--color-border-pale);\n background-color: var(--color-section-bg);\n background-image: url(${___CSS_LOADER_URL_REPLACEMENT_0___});\n background-repeat: no-repeat;\n background-position: 0.5rem center; /* 8px */\n background-size: 1.25rem 1.25rem; /* 20px 20px */\n border-radius: var(--border-radius-base);\n padding: 0 var(--spacing-sm) 0 2.125rem; /* 34px */\n font-size: var(--font-size-base);\n width: 100%;\n box-sizing: border-box;\n}\n\n/* clear button inside search input */\n.contactPane .searchClearButton {\n position: absolute;\n right: var(--spacing-sm);\n top: 50%;\n transform: translateY(-50%);\n border: none;\n background: transparent;\n font-size: var(--font-size-base);\n line-height: 1;\n padding: 0;\n cursor: pointer;\n color: var(--color-text-muted);\n /* visibility is controlled via the generic \\`.hidden\\` utility class */\n display: block;\n}\n.contactPane .searchClearButton.hidden {\n display: none;\n}\n.contactPane .searchClearButton:hover {\n color: var(--color-text);\n}\n\n/* ── Contact toolbar (top-right link + delete) ──────────────── */\n\n.contactPane .contact-toolbar {\n display: flex;\n align-items: center;\n gap: var(--spacing-sm);\n padding: var(--spacing-xs) 0;\n}\n\n.contactPane .contact-toolbar a {\n margin: 0.3rem;\n}\n\n.contactPane .contact-toolbar a img {\n width: 1.3rem;\n height: 1rem;\n margin: 0;\n}\n\n.contact-toolbar .deleteButton {\n margin-left: auto; /* keeps delete icon on the right */\n margin-right: var(--spacing-xxxs, 0.2rem);\n width: var(--icon-xxs, 1rem);\n height: var(--icon-xxs, 1rem);\n float: none; /* important: prevents overlap behavior */\n}\n\n/* ── \"All\" groups button ─────────────────────────────────────── */\n\n.contactPane .allGroupsButton {\n margin-left: var(--spacing-md);\n font-size: var(--font-size-base);\n}\n\n.contactPane .allGroupsButton--loading {\n background-color: var(--color-primary);\n}\n\n.contactPane .allGroupsButton--active {\n background-color: var(--color-primary);\n color: var(--color-background);\n}\n\n.contactPane .allGroupsButton--loaded {\n background-color: var(--color-primary);\n}\n\n/* ── Mint new address book ───────────────────────────────────── */\n\n.contactPane .claimSuccess {\n font-size: var(--font-size-xl);\n}\n\n.contactPane {\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n\n.contactPane .addressBook-grid {\n display: flex;\n flex-wrap: nowrap; /* keep sections side-by-side */\n flex: 1;\n min-width: 0; /* allow it to shrink */\n align-items: stretch;\n width: 100%;\n box-sizing: border-box;\n overflow-x: hidden;\n}\n\n@media ((min-width: 500px) and (max-width: 900px)) {\n .contactPane .addressBookSection {\n max-width: 900px;\n }\n .contactPane .addressBookSection section {\n max-width: 485px;\n }\n}\n\n.contactPane.contactPane--narrow .addressBook-grid {\n flex-direction: column !important;\n flex-wrap: nowrap !important;\n min-width: 0 !important;\n overflow-x: hidden !important;\n}\n\n.contactPane.contactPane--narrow .addressBookSection,\n.contactPane.contactPane--narrow .detailSection {\n flex: 1 1 100% !important;\n max-width: 100% !important;\n min-width: 0 !important;\n width: 100% !important;\n}\n\n@media (max-width: 1000px) {\n /* Stack sidebar + details vertically on narrow screens */\n .contactPane {\n min-height: auto !important;\n }\n\n .contactPane .addressBook-grid {\n flex-direction: column !important;\n flex-wrap: nowrap !important;\n min-height: auto !important;\n height: auto !important;\n }\n\n .contactPane .addressBookSection,\n .contactPane .detailSection {\n order: initial !important;\n flex: none !important;\n width: 100% !important;\n max-width: 100% !important;\n min-width: 0 !important;\n }\n\n\n .contactPane .addressBookSection {\n max-height: none !important;\n min-height: auto !important;\n overflow-y: visible !important;\n padding-bottom: var(--spacing-lg) !important;\n display: flex !important;\n flex-direction: column !important;\n height: auto !important;\n }\n\n .contactPane .peopleSection ul {\n max-height: 50vh;\n overflow-y: auto;\n }\n\n .contactPane .detailSection {\n max-height: none !important;\n min-height: auto !important;\n overflow-y: visible !important;\n }\n\n .contactPane .detailsSectionContent {\n display: flex !important;\n flex-direction: column !important;\n justify-content: flex-start !important;\n align-items: stretch !important;\n min-height: auto !important;\n height: auto !important;\n overflow-y: visible !important;\n }\n\n .contactPane .detailSection > .detailsSectionContent {\n padding-top: var(--spacing-sm) !important;\n box-sizing: border-box !important;\n }\n\n /* Keep a normal mobile text scale while preserving comfortable touch targets */\n /* The following rule made all text much larger on mobile; comment out to restore normal font size for non-buttons.\n .contactPane,\n .contactPane * {\n font-size: 1.5rem !important;\n } */\n\n .contactPane .actionButton,\n .contactPane .searchInput,\n .contactPane .flatButton,\n .contactPane .buttonSection button,\n .contactPane .groupButtonsList button {\n min-height: calc(var(--min-touch-target) + 0.5em) !important;\n font-size: 1.5rem !important;\n padding: 0.875em 1em !important;\n }\n\n .contactPane .group-membership-item .group-membership-toolbar > img.hoverControlHide, .contactPane .group-membership-item .group-membership-toolbar > [data-testid=\"deleteButtonWithCheck\"],\n .individualPane .hoverControl img.hoverControlHide, \n .individualPane .hoverControl [data-testid=\"deleteButtonWithCheck\"] {\n display: inline-flex !important;\n visibility: visible !important;\n opacity: 1 !important;\n }\n}\n\n\n/* Card Section Background */\n.contactPane .addressBookSection.section-bg {\n background: var(--color-section-bg);\n padding: var(--spacing-md);\n box-sizing: border-box;\n border: none !important;\n border-radius: 0 !important;\n}\n\n/* Keep detail section content anchored at top */\n.contactPane .detailSection {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: stretch;\n}\n\n.contactPane .detailsSectionContent {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: stretch;\n}\n\n/* ── Button section: horizontal scrollable row ──────────────── */\n\n\n.contactPane .buttonSection {\n display: flex;\n flex-wrap: nowrap;\n align-items: center;\n padding: var(--spacing-sm);\n padding-bottom: 0;\n overflow-x: auto;\n overflow-y: hidden;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: thin;\n margin-bottom: 0;\n}\n\n@media (max-width: 1000px) {\n .contactPane .buttonSection {\n position: sticky;\n top: 0;\n z-index: 2;\n background: var(--color-section-bg);\n box-shadow: 0 2px 4px -2px rgba(0,0,0,0.04);\n }\n}\n\n.contactPane .buttonSection::-webkit-scrollbar {\n height: 6px;\n}\n\n.contactPane .buttonSection::-webkit-scrollbar-thumb {\n background: var(--color-border-pale);\n border-radius: var(--border-radius-base);\n}\n\n.contactPane .buttonSection::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.contactPane .buttonSection .selected {\n background: none !important;\n}\n\n.contactPane .groupButtonsList {\n display: flex;\n flex-wrap: nowrap;\n align-items: center;\n gap: var(--spacing-xs);\n list-style: none;\n}\n\n.contactPane .buttonSection .groupButtonsList {\n margin-left: var(--spacing-xs);\n margin-right: var(--spacing-xs);\n padding-left: 0;\n}\n\n.contactPane .groupButtonsList li {\n flex-shrink: 0;\n}\n\n.contactPane .groupButtonsList button {\n white-space: nowrap;\n flex-shrink: 0;\n min-width: max-content;\n margin-left: 0;\n}\n\n/* Groups list in details section — flexible 2-column grid */\n.contactPane .detailsSectionContent .groupButtonsList {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n gap: var(--spacing-sm);\n list-style: none;\n padding: 0;\n width: 100%;\n box-sizing: border-box;\n}\n\n.contactPane .detailsSectionContent .groupButtonsList li {\n width: 100%;\n aspect-ratio: auto;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--spacing-xs);\n}\n\n.contactPane .detailsSectionContent .groupButtonsList button {\n width: 100%;\n height: auto;\n text-align: center;\n border-radius: var(--border-radius-base);\n word-wrap: break-word;\n overflow-wrap: break-word;\n}\n\n.contactPane .detailsSectionContent .groupButtonsList li > img.hoverControlHide,\n.contactPane .detailsSectionContent .groupButtonsList li > img[data-testid=\"deleteButtonWithCheck\"] {\n display: block;\n align-self: flex-end;\n float: none !important;\n margin: 0 !important;\n}\n\n@media (max-width: 599px) {\n .contactPane .detailsSectionContent .groupButtonsList {\n grid-template-columns: repeat(2, 1fr);\n gap: var(--spacing-xs);\n }\n\n .contactPane .detailsSectionContent .groupButtonsList button {\n font-size: var(--font-size-sm);\n border-radius: var(--border-radius-base);\n }\n}\n\n@media (min-width: 900px) {\n .contactPane .detailsSectionContent .groupButtonsList {\n grid-template-columns: repeat(3, 1fr);\n }\n}\n\n.contactPane .detailsSectionContent .newGroupBtn {\n width: 100%;\n box-sizing: border-box;\n margin-top: var(--spacing-sm);\n}\n\n.contactPane .detailsSectionContent h3 {\n font-size: var(--font-size-xl);\n margin-bottom: var(--spacing-sm);\n padding-left: 0;\n}\n\n/* Delete confirmation POPUP — centered overlay in details section */\n.contactPane .detailSection {\n position: relative;\n}\n\n.contactPane .webidControl div[style*=\"position: relative\"]:has(> div[style*=\"display: grid\"]) {\n position: static !important;\n}\n\n\n.contactPane .webidControl .personaRow--webid td > div[style*=\"position: relative\"] > div,\n.contactPane .detailsSectionContent .groupButtonsList li > div[style*=\"position: relative\"] > div,\n.contactPane .detailsSectionContent .contact-toolbar > div[style*=\"position: relative\"] > div {\n position: absolute !important;\n left: auto !important;\n z-index: 9999 !important;\n display: grid !important;\n pointer-events: auto !important;\n opacity: 1 !important;\n visibility: visible !important;\n padding: var(--spacing-btn) !important;\n min-width: 12em !important;\n background: var(--color-background) !important;\n border: var(--border-width-sm) solid var(--color-primary) !important;\n border-radius: var(--border-radius-base) !important;\n box-shadow: var(--box-shadow-popup) !important;\n grid-template-columns: auto auto !important;\n gap: var(--spacing-xxs) !important;\n}\n\n.contactPane .detailsSectionContent .contact-toolbar > div[style*=\"position: relative\"] > div > button:has(> img[src\\$=\".svg\"]),\n.contactPane .detailsSectionContent .group-membership-item .group-membership-toolbar > div[style*=\"position: relative\"] > div > button:has(> img[src\\$=\".svg\"]),\n.contactPane .webidControl .personaRow--webid td > div[style*=\"position: relative\"] > div > button:has(> img[src\\$=\".svg\"]) {\n background-color: transparent !important;\n}\n\n/* Selected state for All contacts button */\n.contactPane .allGroupsButton--selected {\n background-color: var(--color-primary);\n color: var(--color-background);\n}\n\n/* ── Header section ──────────────────────────────────────────── */\n\n.contactPane .headerSection {\n background: var(--color-background);\n padding: var(--spacing-sm);\n border-top-left-radius: var(--border-radius-full);\n border-top-right-radius: var(--border-radius-full);\n margin-bottom: 0;\n}\n\n.contactPane .headerSection header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 0;\n}\n\n.contactPane .headerSection h2 {\n margin-bottom: 0;\n}\n\n/* ── Dotted horizontal rule ─────────────────────────────────── */\n\n.contactPane .dottedHr {\n border: none;\n border-top: var(--border-width-sm, 0.1rem) dotted var(--color-text-muted);\n margin: 0;\n}\n\n/* ── Search section ─────────────────────────────────────────── */\n\n.contactPane .searchSection {\n padding: var(--spacing-sm);\n padding-bottom: 0;\n margin-bottom: 0;\n}\n\n/* ── People list section ────────────────────────────────────── */\n\n.contactPane .peopleSection {\n display: flex;\n background: var(--color-background);\n border-top: 1px dotted var(--color-text-muted);\n margin-bottom: 0;\n}\n\n.contactPane .peopleSection ul {\n list-style: none;\n padding: 0;\n margin: 0;\n width: 100%;\n max-height: 70vh;\n overflow-y: auto;\n}\n\n.contactPane .peopleSection li {\n border-top: var(--border-width-sm, 0.1rem) solid var(--color-border-pale);\n padding: var(--spacing-xs);\n}\n\n/* ── Person list item (addressBookPresenter) ─────────────────── */\n\n.contactPane .personLi-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.contactPane .personLi-avatar {\n width: 2.813rem /* 45px */;\n height: 2.813rem /* 45px */;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.contactPane .personLi-avatar .avatar-placeholder {\n width: 2.25rem /* 36px */;\n height: 2.25rem /* 36px */;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.contactPane .personLi-avatar img {\n width: 2.5rem /* 40px */;\n height: 2.5rem /* 40px */;\n border-radius: 50%;\n object-fit: cover;\n}\n\n.contactPane .personLi-info {\n flex: 1;\n margin-left: var(--spacing-sm);\n overflow: hidden;\n}\n\n.contactPane .personLi-name {\n font-weight: bold;\n font-size: var(--font-size-base);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.contactPane .personLi-arrow {\n margin-left: auto;\n display: flex;\n align-items: center;\n}\n\n.contactPane .personLi--error {\n opacity: 0.5;\n}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/contactsPane.css\"],\"names\":[],\"mappings\":\"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\",\"sourcesContent\":[\"/* Focus indicator for keyboard navigation */\\n.contactPane table tr[tabindex=\\\"0\\\"]:focus {\\n outline: var(--focus-ring-width) solid var(--color-primary);\\n outline-offset: 2px;\\n background: var(--color-info-bg);\\n}\\n/* contactsPane styles — extracted from inline styles in contactsPane.js */\\n/* Uses CSS custom properties from the global stylesheet (dev-global.css / mashlib) */\\n\\n/* ── Layout: Three-column browser ────────────────────────────── */\\n\\n.contactPane .peopleSection .selected {\\n background-color: var(--color-info-bg) !important;\\n}\\n\\n.contactPane .detailSection,\\n.contactPane .addressBookSection {\\n display: flex;\\n flex-direction: column;\\n align-items: stretch;\\n flex: 1 1 0; /* allow it to grow but not force wrap */\\n min-width: 0; /* allow sections to collapse when stacked */\\n box-sizing: border-box;\\n background: var(--color-section-bg);\\n}\\n\\n.contactPane .detailsSectionContent {\\n flex: 1 1 auto;\\n min-height: 12.5rem; /* 200px */\\n padding: var(--spacing-lg);\\n max-width: 56.25rem; /* 900px */\\n width: 100%;\\n box-sizing: border-box;\\n}\\n\\n.contactPane .detailsSectionContent--wide {\\n max-width: 56.25rem; /* 900px */\\n}\\n\\n.contactPane .cardFooter {\\n display: flex;\\n flex-wrap: nowrap; /* keep buttons inline */\\n align-items: center; /* vertical centering if varied heights */\\n gap: var(--spacing-xs);\\n padding-top: var(--spacing-md);\\n margin-top: var(--spacing-md);\\n}\\n\\n.contactPane .detailsSectionContent {\\n margin: 0;\\n}\\n\\n/* ── Contact type chooser ───────────────────────────────────── */\\n\\n.contactPane .contactTypeChooser {\\n display: flex;\\n flex-direction: column;\\n gap: var(--spacing-sm);\\n max-width: 22.5rem; /* 360px */\\n}\\n\\n.contactPane .contactTypeChooser h3 {\\n margin: 0 0 var(--spacing-xs) 0;\\n font-size: var(--font-size-lg);\\n}\\n\\n.contactPane .contactTypeSelect {\\n height: var(--min-touch-target);\\n border: var(--border-width-sm, 1px) solid var(--color-border-pale);\\n border-radius: var(--border-radius-base);\\n padding: 0 var(--spacing-sm);\\n font-size: var(--font-size-sm);\\n background: var(--color-section-bg);\\n}\\n\\n/* ── Search ──────────────────────────────────────────────────── */\\n\\n.contactPane .allGroupsButton {\\n border-radius: var(--border-radius-full) !important;\\n /* existing styles */\\n}\\n/* wrapper to position clear icon/button */\\n.contactPane .searchDiv {\\n position: relative;\\n}\\n\\n.contactPane .searchInput {\\n height: var(--min-touch-target);\\n border: var(--border-width-sm, 1px) solid var(--color-border-pale);\\n background-color: var(--color-section-bg);\\n background-image: url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23999' viewBox='0 0 24 24' width='20' height='20'%3E%3Cpath d='M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99c.41.41 1.09.41 1.5 0s.41-1.09 0-1.5l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z'/%3E%3C/svg%3E\\\");\\n background-repeat: no-repeat;\\n background-position: 0.5rem center; /* 8px */\\n background-size: 1.25rem 1.25rem; /* 20px 20px */\\n border-radius: var(--border-radius-base);\\n padding: 0 var(--spacing-sm) 0 2.125rem; /* 34px */\\n font-size: var(--font-size-base);\\n width: 100%;\\n box-sizing: border-box;\\n}\\n\\n/* clear button inside search input */\\n.contactPane .searchClearButton {\\n position: absolute;\\n right: var(--spacing-sm);\\n top: 50%;\\n transform: translateY(-50%);\\n border: none;\\n background: transparent;\\n font-size: var(--font-size-base);\\n line-height: 1;\\n padding: 0;\\n cursor: pointer;\\n color: var(--color-text-muted);\\n /* visibility is controlled via the generic `.hidden` utility class */\\n display: block;\\n}\\n.contactPane .searchClearButton.hidden {\\n display: none;\\n}\\n.contactPane .searchClearButton:hover {\\n color: var(--color-text);\\n}\\n\\n/* ── Contact toolbar (top-right link + delete) ──────────────── */\\n\\n.contactPane .contact-toolbar {\\n display: flex;\\n align-items: center;\\n gap: var(--spacing-sm);\\n padding: var(--spacing-xs) 0;\\n}\\n\\n.contactPane .contact-toolbar a {\\n margin: 0.3rem;\\n}\\n\\n.contactPane .contact-toolbar a img {\\n width: 1.3rem;\\n height: 1rem;\\n margin: 0;\\n}\\n\\n.contact-toolbar .deleteButton {\\n margin-left: auto; /* keeps delete icon on the right */\\n margin-right: var(--spacing-xxxs, 0.2rem);\\n width: var(--icon-xxs, 1rem);\\n height: var(--icon-xxs, 1rem);\\n float: none; /* important: prevents overlap behavior */\\n}\\n\\n/* ── \\\"All\\\" groups button ─────────────────────────────────────── */\\n\\n.contactPane .allGroupsButton {\\n margin-left: var(--spacing-md);\\n font-size: var(--font-size-base);\\n}\\n\\n.contactPane .allGroupsButton--loading {\\n background-color: var(--color-primary);\\n}\\n\\n.contactPane .allGroupsButton--active {\\n background-color: var(--color-primary);\\n color: var(--color-background);\\n}\\n\\n.contactPane .allGroupsButton--loaded {\\n background-color: var(--color-primary);\\n}\\n\\n/* ── Mint new address book ───────────────────────────────────── */\\n\\n.contactPane .claimSuccess {\\n font-size: var(--font-size-xl);\\n}\\n\\n.contactPane {\\n display: flex;\\n flex-direction: column;\\n min-height: 0;\\n}\\n\\n.contactPane .addressBook-grid {\\n display: flex;\\n flex-wrap: nowrap; /* keep sections side-by-side */\\n flex: 1;\\n min-width: 0; /* allow it to shrink */\\n align-items: stretch;\\n width: 100%;\\n box-sizing: border-box;\\n overflow-x: hidden;\\n}\\n\\n@media ((min-width: 500px) and (max-width: 900px)) {\\n .contactPane .addressBookSection {\\n max-width: 900px;\\n }\\n .contactPane .addressBookSection section {\\n max-width: 485px;\\n }\\n}\\n\\n.contactPane.contactPane--narrow .addressBook-grid {\\n flex-direction: column !important;\\n flex-wrap: nowrap !important;\\n min-width: 0 !important;\\n overflow-x: hidden !important;\\n}\\n\\n.contactPane.contactPane--narrow .addressBookSection,\\n.contactPane.contactPane--narrow .detailSection {\\n flex: 1 1 100% !important;\\n max-width: 100% !important;\\n min-width: 0 !important;\\n width: 100% !important;\\n}\\n\\n@media (max-width: 1000px) {\\n /* Stack sidebar + details vertically on narrow screens */\\n .contactPane {\\n min-height: auto !important;\\n }\\n\\n .contactPane .addressBook-grid {\\n flex-direction: column !important;\\n flex-wrap: nowrap !important;\\n min-height: auto !important;\\n height: auto !important;\\n }\\n\\n .contactPane .addressBookSection,\\n .contactPane .detailSection {\\n order: initial !important;\\n flex: none !important;\\n width: 100% !important;\\n max-width: 100% !important;\\n min-width: 0 !important;\\n }\\n\\n\\n .contactPane .addressBookSection {\\n max-height: none !important;\\n min-height: auto !important;\\n overflow-y: visible !important;\\n padding-bottom: var(--spacing-lg) !important;\\n display: flex !important;\\n flex-direction: column !important;\\n height: auto !important;\\n }\\n\\n .contactPane .peopleSection ul {\\n max-height: 50vh;\\n overflow-y: auto;\\n }\\n\\n .contactPane .detailSection {\\n max-height: none !important;\\n min-height: auto !important;\\n overflow-y: visible !important;\\n }\\n\\n .contactPane .detailsSectionContent {\\n display: flex !important;\\n flex-direction: column !important;\\n justify-content: flex-start !important;\\n align-items: stretch !important;\\n min-height: auto !important;\\n height: auto !important;\\n overflow-y: visible !important;\\n }\\n\\n .contactPane .detailSection > .detailsSectionContent {\\n padding-top: var(--spacing-sm) !important;\\n box-sizing: border-box !important;\\n }\\n\\n /* Keep a normal mobile text scale while preserving comfortable touch targets */\\n /* The following rule made all text much larger on mobile; comment out to restore normal font size for non-buttons.\\n .contactPane,\\n .contactPane * {\\n font-size: 1.5rem !important;\\n } */\\n\\n .contactPane .actionButton,\\n .contactPane .searchInput,\\n .contactPane .flatButton,\\n .contactPane .buttonSection button,\\n .contactPane .groupButtonsList button {\\n min-height: calc(var(--min-touch-target) + 0.5em) !important;\\n font-size: 1.5rem !important;\\n padding: 0.875em 1em !important;\\n }\\n\\n .contactPane .group-membership-item .group-membership-toolbar > img.hoverControlHide, .contactPane .group-membership-item .group-membership-toolbar > [data-testid=\\\"deleteButtonWithCheck\\\"],\\n .individualPane .hoverControl img.hoverControlHide, \\n .individualPane .hoverControl [data-testid=\\\"deleteButtonWithCheck\\\"] {\\n display: inline-flex !important;\\n visibility: visible !important;\\n opacity: 1 !important;\\n }\\n}\\n\\n\\n/* Card Section Background */\\n.contactPane .addressBookSection.section-bg {\\n background: var(--color-section-bg);\\n padding: var(--spacing-md);\\n box-sizing: border-box;\\n border: none !important;\\n border-radius: 0 !important;\\n}\\n\\n/* Keep detail section content anchored at top */\\n.contactPane .detailSection {\\n display: flex;\\n flex-direction: column;\\n justify-content: flex-start;\\n align-items: stretch;\\n}\\n\\n.contactPane .detailsSectionContent {\\n display: flex;\\n flex-direction: column;\\n justify-content: flex-start;\\n align-items: stretch;\\n}\\n\\n/* ── Button section: horizontal scrollable row ──────────────── */\\n\\n\\n.contactPane .buttonSection {\\n display: flex;\\n flex-wrap: nowrap;\\n align-items: center;\\n padding: var(--spacing-sm);\\n padding-bottom: 0;\\n overflow-x: auto;\\n overflow-y: hidden;\\n -webkit-overflow-scrolling: touch;\\n scrollbar-width: thin;\\n margin-bottom: 0;\\n}\\n\\n@media (max-width: 1000px) {\\n .contactPane .buttonSection {\\n position: sticky;\\n top: 0;\\n z-index: 2;\\n background: var(--color-section-bg);\\n box-shadow: 0 2px 4px -2px rgba(0,0,0,0.04);\\n }\\n}\\n\\n.contactPane .buttonSection::-webkit-scrollbar {\\n height: 6px;\\n}\\n\\n.contactPane .buttonSection::-webkit-scrollbar-thumb {\\n background: var(--color-border-pale);\\n border-radius: var(--border-radius-base);\\n}\\n\\n.contactPane .buttonSection::-webkit-scrollbar-track {\\n background: transparent;\\n}\\n\\n.contactPane .buttonSection .selected {\\n background: none !important;\\n}\\n\\n.contactPane .groupButtonsList {\\n display: flex;\\n flex-wrap: nowrap;\\n align-items: center;\\n gap: var(--spacing-xs);\\n list-style: none;\\n}\\n\\n.contactPane .buttonSection .groupButtonsList {\\n margin-left: var(--spacing-xs);\\n margin-right: var(--spacing-xs);\\n padding-left: 0;\\n}\\n\\n.contactPane .groupButtonsList li {\\n flex-shrink: 0;\\n}\\n\\n.contactPane .groupButtonsList button {\\n white-space: nowrap;\\n flex-shrink: 0;\\n min-width: max-content;\\n margin-left: 0;\\n}\\n\\n/* Groups list in details section — flexible 2-column grid */\\n.contactPane .detailsSectionContent .groupButtonsList {\\n display: grid;\\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\\n gap: var(--spacing-sm);\\n list-style: none;\\n padding: 0;\\n width: 100%;\\n box-sizing: border-box;\\n}\\n\\n.contactPane .detailsSectionContent .groupButtonsList li {\\n width: 100%;\\n aspect-ratio: auto;\\n display: flex;\\n flex-direction: column;\\n align-items: stretch;\\n gap: var(--spacing-xs);\\n}\\n\\n.contactPane .detailsSectionContent .groupButtonsList button {\\n width: 100%;\\n height: auto;\\n text-align: center;\\n border-radius: var(--border-radius-base);\\n word-wrap: break-word;\\n overflow-wrap: break-word;\\n}\\n\\n.contactPane .detailsSectionContent .groupButtonsList li > img.hoverControlHide,\\n.contactPane .detailsSectionContent .groupButtonsList li > img[data-testid=\\\"deleteButtonWithCheck\\\"] {\\n display: block;\\n align-self: flex-end;\\n float: none !important;\\n margin: 0 !important;\\n}\\n\\n@media (max-width: 599px) {\\n .contactPane .detailsSectionContent .groupButtonsList {\\n grid-template-columns: repeat(2, 1fr);\\n gap: var(--spacing-xs);\\n }\\n\\n .contactPane .detailsSectionContent .groupButtonsList button {\\n font-size: var(--font-size-sm);\\n border-radius: var(--border-radius-base);\\n }\\n}\\n\\n@media (min-width: 900px) {\\n .contactPane .detailsSectionContent .groupButtonsList {\\n grid-template-columns: repeat(3, 1fr);\\n }\\n}\\n\\n.contactPane .detailsSectionContent .newGroupBtn {\\n width: 100%;\\n box-sizing: border-box;\\n margin-top: var(--spacing-sm);\\n}\\n\\n.contactPane .detailsSectionContent h3 {\\n font-size: var(--font-size-xl);\\n margin-bottom: var(--spacing-sm);\\n padding-left: 0;\\n}\\n\\n/* Delete confirmation POPUP — centered overlay in details section */\\n.contactPane .detailSection {\\n position: relative;\\n}\\n\\n.contactPane .webidControl div[style*=\\\"position: relative\\\"]:has(> div[style*=\\\"display: grid\\\"]) {\\n position: static !important;\\n}\\n\\n\\n.contactPane .webidControl .personaRow--webid td > div[style*=\\\"position: relative\\\"] > div,\\n.contactPane .detailsSectionContent .groupButtonsList li > div[style*=\\\"position: relative\\\"] > div,\\n.contactPane .detailsSectionContent .contact-toolbar > div[style*=\\\"position: relative\\\"] > div {\\n position: absolute !important;\\n left: auto !important;\\n z-index: 9999 !important;\\n display: grid !important;\\n pointer-events: auto !important;\\n opacity: 1 !important;\\n visibility: visible !important;\\n padding: var(--spacing-btn) !important;\\n min-width: 12em !important;\\n background: var(--color-background) !important;\\n border: var(--border-width-sm) solid var(--color-primary) !important;\\n border-radius: var(--border-radius-base) !important;\\n box-shadow: var(--box-shadow-popup) !important;\\n grid-template-columns: auto auto !important;\\n gap: var(--spacing-xxs) !important;\\n}\\n\\n.contactPane .detailsSectionContent .contact-toolbar > div[style*=\\\"position: relative\\\"] > div > button:has(> img[src$=\\\".svg\\\"]),\\n.contactPane .detailsSectionContent .group-membership-item .group-membership-toolbar > div[style*=\\\"position: relative\\\"] > div > button:has(> img[src$=\\\".svg\\\"]),\\n.contactPane .webidControl .personaRow--webid td > div[style*=\\\"position: relative\\\"] > div > button:has(> img[src$=\\\".svg\\\"]) {\\n background-color: transparent !important;\\n}\\n\\n/* Selected state for All contacts button */\\n.contactPane .allGroupsButton--selected {\\n background-color: var(--color-primary);\\n color: var(--color-background);\\n}\\n\\n/* ── Header section ──────────────────────────────────────────── */\\n\\n.contactPane .headerSection {\\n background: var(--color-background);\\n padding: var(--spacing-sm);\\n border-top-left-radius: var(--border-radius-full);\\n border-top-right-radius: var(--border-radius-full);\\n margin-bottom: 0;\\n}\\n\\n.contactPane .headerSection header {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n margin-bottom: 0;\\n}\\n\\n.contactPane .headerSection h2 {\\n margin-bottom: 0;\\n}\\n\\n/* ── Dotted horizontal rule ─────────────────────────────────── */\\n\\n.contactPane .dottedHr {\\n border: none;\\n border-top: var(--border-width-sm, 0.1rem) dotted var(--color-text-muted);\\n margin: 0;\\n}\\n\\n/* ── Search section ─────────────────────────────────────────── */\\n\\n.contactPane .searchSection {\\n padding: var(--spacing-sm);\\n padding-bottom: 0;\\n margin-bottom: 0;\\n}\\n\\n/* ── People list section ────────────────────────────────────── */\\n\\n.contactPane .peopleSection {\\n display: flex;\\n background: var(--color-background);\\n border-top: 1px dotted var(--color-text-muted);\\n margin-bottom: 0;\\n}\\n\\n.contactPane .peopleSection ul {\\n list-style: none;\\n padding: 0;\\n margin: 0;\\n width: 100%;\\n max-height: 70vh;\\n overflow-y: auto;\\n}\\n\\n.contactPane .peopleSection li {\\n border-top: var(--border-width-sm, 0.1rem) solid var(--color-border-pale);\\n padding: var(--spacing-xs);\\n}\\n\\n/* ── Person list item (addressBookPresenter) ─────────────────── */\\n\\n.contactPane .personLi-row {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n}\\n\\n.contactPane .personLi-avatar {\\n width: 2.813rem /* 45px */;\\n height: 2.813rem /* 45px */;\\n flex-shrink: 0;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n\\n.contactPane .personLi-avatar .avatar-placeholder {\\n width: 2.25rem /* 36px */;\\n height: 2.25rem /* 36px */;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n\\n.contactPane .personLi-avatar img {\\n width: 2.5rem /* 40px */;\\n height: 2.5rem /* 40px */;\\n border-radius: 50%;\\n object-fit: cover;\\n}\\n\\n.contactPane .personLi-info {\\n flex: 1;\\n margin-left: var(--spacing-sm);\\n overflow: hidden;\\n}\\n\\n.contactPane .personLi-name {\\n font-weight: bold;\\n font-size: var(--font-size-base);\\n white-space: nowrap;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n}\\n\\n.contactPane .personLi-arrow {\\n margin-left: auto;\\n display: flex;\\n align-items: center;\\n}\\n\\n.contactPane .personLi--error {\\n opacity: 0.5;\\n}\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* Solid-UI form */\n\n/* Vertically center autocomplete input in .formFieldValue */\n.individualPane .formFieldValue > div[style*=\"flex-direction: row\"],\n.contactPane .formFieldValue > div[style*=\"flex-direction: row\"] {\n align-items: center;\n display: flex;\n}\n\n.individualPane .formFieldValue input[data-testid=\"autocomplete-input\"],\n.contactPane .formFieldValue input[data-testid=\"autocomplete-input\"] {\n vertical-align: middle;\n}\n\n.individualPane .hoverControl,\n.contactPane .hoverControl {\n position: relative;\n}\n\n/* In contactPane, hover controls in table cells may contain a link + delete icon.\n Make the cell grow and keep the delete icon right-aligned (no overlap). */\n.contactPane td.hoverControl:has(> a) {\n width: auto !important;\n min-width: 4rem !important;\n justify-content: space-between !important;\n}\n\n.contactPane td.hoverControl:has(> a) > a {\n flex: 1 1 auto;\n min-width: 0;\n overflow-wrap: anywhere;\n word-break: break-word;\n white-space: normal;\n}\n\n.individualPane .hoverControl:has(> img:first-child),\n.contactPane .hoverControl:has(> img:first-child) {\n background-color: transparent !important;\n border: none !important;\n margin: 0 !important;\n border-radius: 0 !important;\n padding: var(--spacing-btn) !important;\n min-height: var(--min-touch-target);\n min-width: var(--min-touch-target);\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n\n.individualPane .hoverControl:has(> img:first-child) > span,\n.contactPane .hoverControl:has(> img:first-child) > span {\n display: inline-flex;\n align-items: center;\n margin-left: var(--spacing-xxs);\n}\n\n.individualPane div[style*=\"padding: 0.5em\"]:has(> img),\n.contactPane div[style*=\"padding: 0.5em\"]:has(> img) {\n display: inline-flex;\n align-items: center;\n}\n\n.individualPane div[style*=\"padding: 0.5em\"]:has(> img) > span,\n.contactPane div[style*=\"padding: 0.5em\"]:has(> img) > span {\n margin-left: var(--spacing-xxs);\n}\n\n.individualPane .hoverControl:has(> img:first-child):hover,\n.contactPane .hoverControl:has(> img:first-child):hover {\n background-color: var(--color-section-bg) !important;\n}\n\n.individualPane button:has(> img[src\\$=\".svg\"]),\n.contactPane button:has(> img[src\\$=\".svg\"]) {\n background-color: var(--color-section-bg) !important;\n border: none !important;\n margin: 0 !important;\n border-radius: 0 !important;\n box-shadow: none !important;\n transition: background-color 0.2s ease, box-shadow 0.2s ease;\n}\n\n/* Ensure certain icon images render at a consistent size and align nicely when adjacent. */\n.contactPane img[src\\$=\"red.svg\"],\n.contactPane img[src\\$=\"go-to-this.png\"],\n.individualPane img[src\\$=\"red.svg\"],\n.individualPane img[src\\$=\"go-to-this.png\"] {\n width: 1.2rem !important;\n height: 1.2rem !important;\n max-width: none !important;\n max-height: none !important;\n object-fit: contain;\n display: inline-block;\n vertical-align: middle;\n}\n\n/* If the SVG button is inside a statsLog wrapper, add pink background to the button only. */\n.individualPane .statsLog button:has(> img[src\\$=\".svg\"]),\n.contactPane .statsLog button:has(> img[src\\$=\".svg\"]) {\n background-color: var(--color-info-bg) !important;\n border: initial !important;\n margin: initial !important;\n border-radius: initial !important;\n}\n\n/* Hide the “Continue” icon button that Solid-UI sometimes renders below textareas. */\n.individualPane button:has(> img[title=\"Continue\"]),\n.contactPane button:has(> img[title=\"Continue\"]) {\n display: none !important;\n}\n\n.contactPane .detailSection .detailsSectionContent button:has(> img[title=\"Continue\"]),\n.contactPane .detailSection .detailsSectionContent img[title=\"Continue\"] {\n display: inline-flex !important;\n}\n\n.contactPane .detailSection .detailsSectionContent img[title=\"Continue\"] {\n width: var(--icon-base, 2rem) !important;\n height: var(--icon-base, 2rem) !important;\n}\n\n/* Allow “Continue” buttons inside contactFormContainer to be visible. */\n.individualPane .contactFormContainer button:has(> img[src\\$=\"noun_1180158.svg\"]),\n.contactPane .contactFormContainer button:has(> img[src\\$=\"noun_1180158.svg\"]),\n.individualPane .contactFormContainer button:has(> img[title=\"Continue\"]),\n.contactPane .contactFormContainer button:has(> img[title=\"Continue\"]) {\n display: inline-flex !important;\n}\n\n/* Exception: allow “Continue” buttons inside statsLog to remain visible. */\n.individualPane .statsLog button:has(> img[title=\"Continue\"]),\n.contactPane .statsLog button:has(> img[title=\"Continue\"]),\n.individualPane .webidControl button:has(> img[title=\"Continue\"]),\n.contactPane .webidControl button:has(> img[title=\"Continue\"]){\n display: inline-flex !important;\n}\n\n.individualPane button,\n.contactPane button {\n min-height: var(--min-touch-target);\n min-width: var(--min-touch-target);\n}\n\n.individualPane input:not([type=\"color\"]),\n.contactPane input:not([type=\"color\"]) {\n width: 99%;\n max-width: 99%;\n min-width: 0;\n box-sizing: border-box;\n font: inherit;\n color: var(--color-text);\n background-color: var(--color-card-bg) !important;\n border: var(--border-width-sm) solid var(--color-border-pale);\n margin-left: 0 !important;\n margin-right: 0 !important;\n}\n\n.individualPane textarea,\n.contactPane textarea,\n.individualPane .formFieldValue textarea,\n.contactPane .formFieldValue textarea {\n appearance: none;\n -webkit-appearance: none;\n border-radius: var(--border-radius-sm) !important;\n border: var(--border-width-xthin) solid var(--color-border-accent) !important;\n width: 99%;\n max-width: 99%;\n box-sizing: border-box;\n font: inherit;\n color: var(--color-text);\n background-color: var(--color-card-bg) !important;\n margin: 0 !important;\n margin-top: var(--spacing-xs);\n margin-left: 0 !important;\n margin-right: 0 !important;\n padding: var(--spacing-xs) !important;\n}\n\n.individualPane select,\n.contactPane select {\n max-width: 99%;\n min-width: 0;\n box-sizing: border-box;\n font: inherit;\n color: var(--color-text);\n background-color: var(--color-card-bg) !important;\n border: var(--border-width-sm) solid var(--color-border-pale);\n}\n\n.individualPane input[type=\"date\"],\n.contactPane input[type=\"date\"],\n.individualPane input[type=\"month\"],\n.contactPane input[type=\"month\"],\n.individualPane input[type=\"week\"],\n.contactPane input[type=\"week\"],\n.individualPane input[type=\"time\"],\n.contactPane input[type=\"time\"],\n.individualPane input[type=\"datetime-local\"],\n.contactPane input[type=\"datetime-local\"] {\n min-height: var(--min-touch-target);\n}\n\n.individualPane .hoverControl:has(> img:first-child):focus-visible,\n.contactPane .hoverControl:has(> img:first-child):focus-visible,\n.individualPane button:focus-visible,\n.contactPane button:focus-visible,\n.individualPane input:not([type=\"color\"]):focus-visible,\n.contactPane input:not([type=\"color\"]):focus-visible,\n.individualPane textarea:focus-visible,\n.contactPane textarea:focus-visible,\n.individualPane select:focus-visible,\n.contactPane select:focus-visible {\n outline: var(--focus-ring-width) solid var(--color-primary) !important;\n outline-offset: 2px;\n box-shadow: 0 0 0 1px var(--color-background);\n}\n\n.individualPane input[type=\"url\"],\n.contactPane input[type=\"url\"] {\n width: 99%;\n}\n\n.individualPane .formFieldValue,\n.contactPane .formFieldValue {\n min-width: 0;\n margin-bottom: var(--spacing-sm);\n}\n\n.individualPane .formFieldValue table,\n.contactPane .formFieldValue table {\n margin: 0 !important;\n padding: 0 !important;\n}\n\n.individualPane .formFieldValue td,\n.contactPane .formFieldValue td {\n padding: 0 !important;\n vertical-align: middle;\n}\n\n.individualPane .formFieldValue table[data-testid=\"autocomplete-table\"],\n.contactPane .formFieldValue table[data-testid=\"autocomplete-table\"] {\n height: 100%;\n}\n\n.individualPane .formFieldValue input:not([type=\"color\"]),\n.contactPane .formFieldValue input:not([type=\"color\"]),\n.individualPane .formFieldValue textarea,\n.contactPane .formFieldValue textarea {\n width: 99% !important;\n max-width: 99%;\n}\n\n/* Email and phone value inputs: do not stretch full width */\n.individualPane .formFieldName:has(a[href=\"http://www.w3.org/2006/vcard/ns#value\"]) + .formFieldValue input:not([type=\"color\"]),\n.contactPane .formFieldName:has(a[href=\"http://www.w3.org/2006/vcard/ns#value\"]) + .formFieldValue input:not([type=\"color\"]) {\n width: 98% !important;\n max-width: 98%;\n}\n\n.individualPane .formFieldValue select,\n.contactPane .formFieldValue select {\n width: 99%;\n display: inline-block;\n max-width: none !important;\n}\n\n.individualPane select#formSelect,\n.contactPane select#formSelect {\n width: 99%;\n max-width: 98%;\n box-sizing: border-box;\n margin-left: 0 !important;\n margin-right: 0 !important;\n}\n\n.individualPane span select,\n.contactPane span select {\n max-width: 96% !important;\n box-sizing: border-box;\n margin: 0 !important;\n}\n\n.individualPane .formFieldValue span select,\n.contactPane .formFieldValue span select {\n margin-left: 0 !important;\n margin-right: 0 !important;\n}\n\n/* Remove border/padding from the first wrapper div (and its first child wrapper). */\n.individualPane > div:first-of-type,\n.contactPane > div:first-of-type,\n.individualPane > div:first-of-type > div:first-of-type,\n.contactPane > div:first-of-type > div:first-of-type {\n border: none !important;\n padding: 0 !important;\n}\n\n/* In contactPane, remove border/padding from all direct child divs. */\n.individualPane > div,\n.contactPane > div {\n border: none !important;\n padding: 0 !important;\n}\n\n/* Align schema.org, solid terms, FOAF, vCard, and org field labels with their input values. */\n.individualPane :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue),\n.contactPane :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue) {\n display: flex;\n align-items: baseline;\n margin-bottom: var(--spacing-sm);\n}\n\n/* for the Resume inside corporation choice */\n/* Add space between classifierBox label and select box */\n.individualPane .choiceBox .classifierBox-label,\n.contactPane .choiceBox .classifierBox-label {\n margin-right: 0;\n padding-left: var(--spacing-xxs);\n}\n\n.individualPane .choiceBox .choiceBox-selectBox select,\n.contactPane .choiceBox .choiceBox-selectBox select {\n margin-left: 2.1rem !important;\n}\n\n/* for the Resume orga details */\n/* Add space between classifierBox label and select box */\n.individualPane .classifierBox .classifierBox-label,\n.contactPane .classifierBox .classifierBox-label {\n margin-right: 0;\n padding-left: var(--spacing-xxs);\n width: 8rem;\n padding: var(--spacing-xxs);\n vertical-align: middle;\n}\n\n.individualPane .classifierBox .classifierBox-selectBox,\n.contactPane .classifierBox .classifierBox-selectBox {\n margin-left: 0 !important;\n}\n\n.individualPane .classifierBox .classifierBox-selectBox select,\n.contactPane .classifierBox .classifierBox-selectBox select {\n margin-left: 0 !important;\n}\n\n.individualPane .formFieldValue > span > select,\n.contactPane .formFieldValue > span > select {\n margin-left: 0 !important;\n}\n\n.individualPane :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue) > .formFieldValue,\n.contactPane :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue) > .formFieldValue {\n margin-bottom: 0;\n}\n\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://schema.org/\"]),\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://schema.org/\"]),\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/ns/solid/terms#\"]),\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/ns/solid/terms#\"]),\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://xmlns.com/foaf/0.1/\"]),\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://xmlns.com/foaf/0.1/\"]),\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/2006/vcard/ns\"]),\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/2006/vcard/ns\"]),\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/ns/org#\"]),\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/ns/org#\"]) {\n display: inline-flex;\n align-items: center;\n vertical-align: middle;\n}\n\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://schema.org/\"]) + .formFieldValue,\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://schema.org/\"]) + .formFieldValue,\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/ns/solid/terms#\"]) + .formFieldValue,\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/ns/solid/terms#\"]) + .formFieldValue,\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://xmlns.com/foaf/0.1/\"]) + .formFieldValue,\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://xmlns.com/foaf/0.1/\"]) + .formFieldValue,\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/2006/vcard/ns\"]) + .formFieldValue,\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/2006/vcard/ns\"]) + .formFieldValue,\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/ns/org#\"]) + .formFieldValue,\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\"http://www.w3.org/ns/org#\"]) + .formFieldValue {\n display: inline-flex;\n align-items: center;\n vertical-align: middle;\n flex: 1;\n min-width: 0;\n}\n\n/* Center textarea label vertically in flex rows. */\n.individualPane div[style*=\"display: flex\"][style*=\"flex-direction: row\"]:has(textarea),\n.contactPane div[style*=\"display: flex\"][style*=\"flex-direction: row\"]:has(textarea) {\n align-items: flex-start;\n}\n\n.individualPane div[style*=\"display: flex\"][style*=\"flex-direction: row\"]:has(textarea) > div:has(> a),\n.contactPane div[style*=\"display: flex\"][style*=\"flex-direction: row\"]:has(textarea) > div:has(> a) {\n padding-left: var(--spacing-xs);\n padding-top: var(--spacing-sm);\n}\n\n/* Keep autocomplete/table-based fields (e.g. Occupation) aligned to label text baseline. */\n.individualPane :not(.choiceBox):has(> .formFieldValue input[data-testid=\"autocomplete-input\"]),\n.contactPane :not(.choiceBox):has(> .formFieldValue input[data-testid=\"autocomplete-input\"]) {\n align-items: flex-start;\n}\n\n.individualPane :not(.choiceBox):has(> .formFieldValue input[data-testid=\"autocomplete-input\"]) > .formFieldName,\n.contactPane :not(.choiceBox):has(> .formFieldValue input[data-testid=\"autocomplete-input\"]) > .formFieldName {\n padding-top: var(--spacing-xs) !important;\n}\n\n.individualPane .formFieldValue:has(input[data-testid=\"autocomplete-input\"]),\n.contactPane .formFieldValue:has(input[data-testid=\"autocomplete-input\"]) {\n align-self: flex-start;\n}\n\n.individualPane .formFieldValue table[data-testid=\"autocomplete-table\"],\n.contactPane .formFieldValue table[data-testid=\"autocomplete-table\"],\n.individualPane .formFieldValue input[data-testid=\"autocomplete-input\"],\n.contactPane .formFieldValue input[data-testid=\"autocomplete-input\"] {\n margin: 0 !important;\n}\n\n.individualPane .formFieldValue table[data-testid=\"autocomplete-table\"],\n.contactPane .formFieldValue table[data-testid=\"autocomplete-table\"] {\n vertical-align: baseline;\n}\n\n.individualPane input:disabled,\n.contactPane input:disabled,\n.individualPane textarea:disabled,\n.contactPane textarea:disabled,\n.individualPane select:disabled,\n.contactPane select:disabled,\n.individualPane input[readonly],\n.contactPane input[readonly],\n.individualPane textarea[readonly],\n.contactPane textarea[readonly],\n.individualPane input:read-only,\n.contactPane input:read-only,\n.individualPane textarea:read-only,\n.contactPane textarea:read-only {\n background-color: var(--color-background) !important;\n cursor: not-allowed;\n opacity: var(--opacity-input-disabled);\n border: var(--border-width-xthin) solid var(--color-background) !important;\n}\n\n.contactPane .webidControl table td div.contactPane.namedPane {\n border: none !important;\n}\n\n/* ------------------------------------------------------------------ */\n/* inline popup used for small confirmation flows (like the new confirmDialog) */\n/* apply the class \\`rdf-inline-modal\\` on the outer wrapper and give the\n inner box the class \\`popup\\` instead of using the old inline styles. */\n\n/* selectors that match the old inline-styled markup when no classes can be added */\n\n/* Delete pop up */\n/* Remove the intermediate positioned ancestor so the popup anchors to .hoverControl instead */\n.individualPane div[style*=\"position: relative\"]:has(> div[style*=\"display: grid\"]) {\n position: static !important;\n}\n\n.individualPane div[style*=\"position: relative\"] > div[style*=\"display: grid\"] {\n /* override inline values with theme variables */\n position: absolute !important;\n top: 0 !important;\n right: 0 !important;\n left: auto !important;\n z-index: 9999 !important;\n display: grid !important;\n pointer-events: auto !important;\n opacity: 1 !important;\n visibility: visible !important;\n padding: var(--spacing-btn) !important;\n background: var(--color-background) !important;\n border: var(--border-width-sm) solid var(--color-primary) !important;\n border-radius: var(--border-radius-base) !important;\n box-shadow: var(--box-shadow-popup) !important;\n grid-template-columns: auto auto !important;\n gap: var(--spacing-xxs) !important;\n}\n\n.individualPane .hoverControl img.hoverControlHide,\n.individualPane .hoverControl [data-testid=\"deleteButtonWithCheck\"] {\n position: absolute !important;\n right: var(--spacing-xxxs) !important;\n width: var(--icon-xs, 1.5rem) !important;\n height: var(--icon-xs, 1.5rem) !important;\n display: none !important;\n align-items: center;\n justify-content: center;\n margin: 0 !important;\n float: none !important;\n z-index: 2 !important;\n}\n\n/* Show delete icon only on hover */\n.individualPane .hoverControl:hover img.hoverControlHide,\n.individualPane .hoverControl:hover [data-testid=\"deleteButtonWithCheck\"] {\n display: inline-flex !important;\n}\n\n/* If the hoverControl has exactly one div + the delete icon, keep the icon vertically centered but right-aligned */\n.individualPane .hoverControl:has(> div:nth-child(1):nth-last-child(2)):hover > img.hoverControlHide,\n.individualPane .hoverControl:has(> div:nth-child(1):nth-last-child(2)):hover > [data-testid=\"deleteButtonWithCheck\"] {\n top: 50% !important;\n right: var(--spacing-xxxs) !important;\n left: auto !important;\n transform: translateY(-50%) !important;\n}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/contactsRDFFormsEnforced.css\"],\"names\":[],\"mappings\":\"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\",\"sourcesContent\":[\"/* Solid-UI form */\\n\\n/* Vertically center autocomplete input in .formFieldValue */\\n.individualPane .formFieldValue > div[style*=\\\"flex-direction: row\\\"],\\n.contactPane .formFieldValue > div[style*=\\\"flex-direction: row\\\"] {\\n align-items: center;\\n display: flex;\\n}\\n\\n.individualPane .formFieldValue input[data-testid=\\\"autocomplete-input\\\"],\\n.contactPane .formFieldValue input[data-testid=\\\"autocomplete-input\\\"] {\\n vertical-align: middle;\\n}\\n\\n.individualPane .hoverControl,\\n.contactPane .hoverControl {\\n position: relative;\\n}\\n\\n/* In contactPane, hover controls in table cells may contain a link + delete icon.\\n Make the cell grow and keep the delete icon right-aligned (no overlap). */\\n.contactPane td.hoverControl:has(> a) {\\n width: auto !important;\\n min-width: 4rem !important;\\n justify-content: space-between !important;\\n}\\n\\n.contactPane td.hoverControl:has(> a) > a {\\n flex: 1 1 auto;\\n min-width: 0;\\n overflow-wrap: anywhere;\\n word-break: break-word;\\n white-space: normal;\\n}\\n\\n.individualPane .hoverControl:has(> img:first-child),\\n.contactPane .hoverControl:has(> img:first-child) {\\n background-color: transparent !important;\\n border: none !important;\\n margin: 0 !important;\\n border-radius: 0 !important;\\n padding: var(--spacing-btn) !important;\\n min-height: var(--min-touch-target);\\n min-width: var(--min-touch-target);\\n cursor: pointer;\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n}\\n\\n.individualPane .hoverControl:has(> img:first-child) > span,\\n.contactPane .hoverControl:has(> img:first-child) > span {\\n display: inline-flex;\\n align-items: center;\\n margin-left: var(--spacing-xxs);\\n}\\n\\n.individualPane div[style*=\\\"padding: 0.5em\\\"]:has(> img),\\n.contactPane div[style*=\\\"padding: 0.5em\\\"]:has(> img) {\\n display: inline-flex;\\n align-items: center;\\n}\\n\\n.individualPane div[style*=\\\"padding: 0.5em\\\"]:has(> img) > span,\\n.contactPane div[style*=\\\"padding: 0.5em\\\"]:has(> img) > span {\\n margin-left: var(--spacing-xxs);\\n}\\n\\n.individualPane .hoverControl:has(> img:first-child):hover,\\n.contactPane .hoverControl:has(> img:first-child):hover {\\n background-color: var(--color-section-bg) !important;\\n}\\n\\n.individualPane button:has(> img[src$=\\\".svg\\\"]),\\n.contactPane button:has(> img[src$=\\\".svg\\\"]) {\\n background-color: var(--color-section-bg) !important;\\n border: none !important;\\n margin: 0 !important;\\n border-radius: 0 !important;\\n box-shadow: none !important;\\n transition: background-color 0.2s ease, box-shadow 0.2s ease;\\n}\\n\\n/* Ensure certain icon images render at a consistent size and align nicely when adjacent. */\\n.contactPane img[src$=\\\"red.svg\\\"],\\n.contactPane img[src$=\\\"go-to-this.png\\\"],\\n.individualPane img[src$=\\\"red.svg\\\"],\\n.individualPane img[src$=\\\"go-to-this.png\\\"] {\\n width: 1.2rem !important;\\n height: 1.2rem !important;\\n max-width: none !important;\\n max-height: none !important;\\n object-fit: contain;\\n display: inline-block;\\n vertical-align: middle;\\n}\\n\\n/* If the SVG button is inside a statsLog wrapper, add pink background to the button only. */\\n.individualPane .statsLog button:has(> img[src$=\\\".svg\\\"]),\\n.contactPane .statsLog button:has(> img[src$=\\\".svg\\\"]) {\\n background-color: var(--color-info-bg) !important;\\n border: initial !important;\\n margin: initial !important;\\n border-radius: initial !important;\\n}\\n\\n/* Hide the “Continue” icon button that Solid-UI sometimes renders below textareas. */\\n.individualPane button:has(> img[title=\\\"Continue\\\"]),\\n.contactPane button:has(> img[title=\\\"Continue\\\"]) {\\n display: none !important;\\n}\\n\\n.contactPane .detailSection .detailsSectionContent button:has(> img[title=\\\"Continue\\\"]),\\n.contactPane .detailSection .detailsSectionContent img[title=\\\"Continue\\\"] {\\n display: inline-flex !important;\\n}\\n\\n.contactPane .detailSection .detailsSectionContent img[title=\\\"Continue\\\"] {\\n width: var(--icon-base, 2rem) !important;\\n height: var(--icon-base, 2rem) !important;\\n}\\n\\n/* Allow “Continue” buttons inside contactFormContainer to be visible. */\\n.individualPane .contactFormContainer button:has(> img[src$=\\\"noun_1180158.svg\\\"]),\\n.contactPane .contactFormContainer button:has(> img[src$=\\\"noun_1180158.svg\\\"]),\\n.individualPane .contactFormContainer button:has(> img[title=\\\"Continue\\\"]),\\n.contactPane .contactFormContainer button:has(> img[title=\\\"Continue\\\"]) {\\n display: inline-flex !important;\\n}\\n\\n/* Exception: allow “Continue” buttons inside statsLog to remain visible. */\\n.individualPane .statsLog button:has(> img[title=\\\"Continue\\\"]),\\n.contactPane .statsLog button:has(> img[title=\\\"Continue\\\"]),\\n.individualPane .webidControl button:has(> img[title=\\\"Continue\\\"]),\\n.contactPane .webidControl button:has(> img[title=\\\"Continue\\\"]){\\n display: inline-flex !important;\\n}\\n\\n.individualPane button,\\n.contactPane button {\\n min-height: var(--min-touch-target);\\n min-width: var(--min-touch-target);\\n}\\n\\n.individualPane input:not([type=\\\"color\\\"]),\\n.contactPane input:not([type=\\\"color\\\"]) {\\n width: 99%;\\n max-width: 99%;\\n min-width: 0;\\n box-sizing: border-box;\\n font: inherit;\\n color: var(--color-text);\\n background-color: var(--color-card-bg) !important;\\n border: var(--border-width-sm) solid var(--color-border-pale);\\n margin-left: 0 !important;\\n margin-right: 0 !important;\\n}\\n\\n.individualPane textarea,\\n.contactPane textarea,\\n.individualPane .formFieldValue textarea,\\n.contactPane .formFieldValue textarea {\\n appearance: none;\\n -webkit-appearance: none;\\n border-radius: var(--border-radius-sm) !important;\\n border: var(--border-width-xthin) solid var(--color-border-accent) !important;\\n width: 99%;\\n max-width: 99%;\\n box-sizing: border-box;\\n font: inherit;\\n color: var(--color-text);\\n background-color: var(--color-card-bg) !important;\\n margin: 0 !important;\\n margin-top: var(--spacing-xs);\\n margin-left: 0 !important;\\n margin-right: 0 !important;\\n padding: var(--spacing-xs) !important;\\n}\\n\\n.individualPane select,\\n.contactPane select {\\n max-width: 99%;\\n min-width: 0;\\n box-sizing: border-box;\\n font: inherit;\\n color: var(--color-text);\\n background-color: var(--color-card-bg) !important;\\n border: var(--border-width-sm) solid var(--color-border-pale);\\n}\\n\\n.individualPane input[type=\\\"date\\\"],\\n.contactPane input[type=\\\"date\\\"],\\n.individualPane input[type=\\\"month\\\"],\\n.contactPane input[type=\\\"month\\\"],\\n.individualPane input[type=\\\"week\\\"],\\n.contactPane input[type=\\\"week\\\"],\\n.individualPane input[type=\\\"time\\\"],\\n.contactPane input[type=\\\"time\\\"],\\n.individualPane input[type=\\\"datetime-local\\\"],\\n.contactPane input[type=\\\"datetime-local\\\"] {\\n min-height: var(--min-touch-target);\\n}\\n\\n.individualPane .hoverControl:has(> img:first-child):focus-visible,\\n.contactPane .hoverControl:has(> img:first-child):focus-visible,\\n.individualPane button:focus-visible,\\n.contactPane button:focus-visible,\\n.individualPane input:not([type=\\\"color\\\"]):focus-visible,\\n.contactPane input:not([type=\\\"color\\\"]):focus-visible,\\n.individualPane textarea:focus-visible,\\n.contactPane textarea:focus-visible,\\n.individualPane select:focus-visible,\\n.contactPane select:focus-visible {\\n outline: var(--focus-ring-width) solid var(--color-primary) !important;\\n outline-offset: 2px;\\n box-shadow: 0 0 0 1px var(--color-background);\\n}\\n\\n.individualPane input[type=\\\"url\\\"],\\n.contactPane input[type=\\\"url\\\"] {\\n width: 99%;\\n}\\n\\n.individualPane .formFieldValue,\\n.contactPane .formFieldValue {\\n min-width: 0;\\n margin-bottom: var(--spacing-sm);\\n}\\n\\n.individualPane .formFieldValue table,\\n.contactPane .formFieldValue table {\\n margin: 0 !important;\\n padding: 0 !important;\\n}\\n\\n.individualPane .formFieldValue td,\\n.contactPane .formFieldValue td {\\n padding: 0 !important;\\n vertical-align: middle;\\n}\\n\\n.individualPane .formFieldValue table[data-testid=\\\"autocomplete-table\\\"],\\n.contactPane .formFieldValue table[data-testid=\\\"autocomplete-table\\\"] {\\n height: 100%;\\n}\\n\\n.individualPane .formFieldValue input:not([type=\\\"color\\\"]),\\n.contactPane .formFieldValue input:not([type=\\\"color\\\"]),\\n.individualPane .formFieldValue textarea,\\n.contactPane .formFieldValue textarea {\\n width: 99% !important;\\n max-width: 99%;\\n}\\n\\n/* Email and phone value inputs: do not stretch full width */\\n.individualPane .formFieldName:has(a[href=\\\"http://www.w3.org/2006/vcard/ns#value\\\"]) + .formFieldValue input:not([type=\\\"color\\\"]),\\n.contactPane .formFieldName:has(a[href=\\\"http://www.w3.org/2006/vcard/ns#value\\\"]) + .formFieldValue input:not([type=\\\"color\\\"]) {\\n width: 98% !important;\\n max-width: 98%;\\n}\\n\\n.individualPane .formFieldValue select,\\n.contactPane .formFieldValue select {\\n width: 99%;\\n display: inline-block;\\n max-width: none !important;\\n}\\n\\n.individualPane select#formSelect,\\n.contactPane select#formSelect {\\n width: 99%;\\n max-width: 98%;\\n box-sizing: border-box;\\n margin-left: 0 !important;\\n margin-right: 0 !important;\\n}\\n\\n.individualPane span select,\\n.contactPane span select {\\n max-width: 96% !important;\\n box-sizing: border-box;\\n margin: 0 !important;\\n}\\n\\n.individualPane .formFieldValue span select,\\n.contactPane .formFieldValue span select {\\n margin-left: 0 !important;\\n margin-right: 0 !important;\\n}\\n\\n/* Remove border/padding from the first wrapper div (and its first child wrapper). */\\n.individualPane > div:first-of-type,\\n.contactPane > div:first-of-type,\\n.individualPane > div:first-of-type > div:first-of-type,\\n.contactPane > div:first-of-type > div:first-of-type {\\n border: none !important;\\n padding: 0 !important;\\n}\\n\\n/* In contactPane, remove border/padding from all direct child divs. */\\n.individualPane > div,\\n.contactPane > div {\\n border: none !important;\\n padding: 0 !important;\\n}\\n\\n/* Align schema.org, solid terms, FOAF, vCard, and org field labels with their input values. */\\n.individualPane :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue),\\n.contactPane :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue) {\\n display: flex;\\n align-items: baseline;\\n margin-bottom: var(--spacing-sm);\\n}\\n\\n/* for the Resume inside corporation choice */\\n/* Add space between classifierBox label and select box */\\n.individualPane .choiceBox .classifierBox-label,\\n.contactPane .choiceBox .classifierBox-label {\\n margin-right: 0;\\n padding-left: var(--spacing-xxs);\\n}\\n\\n.individualPane .choiceBox .choiceBox-selectBox select,\\n.contactPane .choiceBox .choiceBox-selectBox select {\\n margin-left: 2.1rem !important;\\n}\\n\\n/* for the Resume orga details */\\n/* Add space between classifierBox label and select box */\\n.individualPane .classifierBox .classifierBox-label,\\n.contactPane .classifierBox .classifierBox-label {\\n margin-right: 0;\\n padding-left: var(--spacing-xxs);\\n width: 8rem;\\n padding: var(--spacing-xxs);\\n vertical-align: middle;\\n}\\n\\n.individualPane .classifierBox .classifierBox-selectBox,\\n.contactPane .classifierBox .classifierBox-selectBox {\\n margin-left: 0 !important;\\n}\\n\\n.individualPane .classifierBox .classifierBox-selectBox select,\\n.contactPane .classifierBox .classifierBox-selectBox select {\\n margin-left: 0 !important;\\n}\\n\\n.individualPane .formFieldValue > span > select,\\n.contactPane .formFieldValue > span > select {\\n margin-left: 0 !important;\\n}\\n\\n.individualPane :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue) > .formFieldValue,\\n.contactPane :not(.choiceBox):has(> .formFieldName):has(> .formFieldValue) > .formFieldValue {\\n margin-bottom: 0;\\n}\\n\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://schema.org/\\\"]),\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://schema.org/\\\"]),\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/ns/solid/terms#\\\"]),\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/ns/solid/terms#\\\"]),\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://xmlns.com/foaf/0.1/\\\"]),\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://xmlns.com/foaf/0.1/\\\"]),\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/2006/vcard/ns\\\"]),\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/2006/vcard/ns\\\"]),\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/ns/org#\\\"]),\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/ns/org#\\\"]) {\\n display: inline-flex;\\n align-items: center;\\n vertical-align: middle;\\n}\\n\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://schema.org/\\\"]) + .formFieldValue,\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://schema.org/\\\"]) + .formFieldValue,\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/ns/solid/terms#\\\"]) + .formFieldValue,\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/ns/solid/terms#\\\"]) + .formFieldValue,\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://xmlns.com/foaf/0.1/\\\"]) + .formFieldValue,\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://xmlns.com/foaf/0.1/\\\"]) + .formFieldValue,\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/2006/vcard/ns\\\"]) + .formFieldValue,\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/2006/vcard/ns\\\"]) + .formFieldValue,\\n.individualPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/ns/org#\\\"]) + .formFieldValue,\\n.contactPane :not(.choiceBox) > .formFieldName:has(a[href*=\\\"http://www.w3.org/ns/org#\\\"]) + .formFieldValue {\\n display: inline-flex;\\n align-items: center;\\n vertical-align: middle;\\n flex: 1;\\n min-width: 0;\\n}\\n\\n/* Center textarea label vertically in flex rows. */\\n.individualPane div[style*=\\\"display: flex\\\"][style*=\\\"flex-direction: row\\\"]:has(textarea),\\n.contactPane div[style*=\\\"display: flex\\\"][style*=\\\"flex-direction: row\\\"]:has(textarea) {\\n align-items: flex-start;\\n}\\n\\n.individualPane div[style*=\\\"display: flex\\\"][style*=\\\"flex-direction: row\\\"]:has(textarea) > div:has(> a),\\n.contactPane div[style*=\\\"display: flex\\\"][style*=\\\"flex-direction: row\\\"]:has(textarea) > div:has(> a) {\\n padding-left: var(--spacing-xs);\\n padding-top: var(--spacing-sm);\\n}\\n\\n/* Keep autocomplete/table-based fields (e.g. Occupation) aligned to label text baseline. */\\n.individualPane :not(.choiceBox):has(> .formFieldValue input[data-testid=\\\"autocomplete-input\\\"]),\\n.contactPane :not(.choiceBox):has(> .formFieldValue input[data-testid=\\\"autocomplete-input\\\"]) {\\n align-items: flex-start;\\n}\\n\\n.individualPane :not(.choiceBox):has(> .formFieldValue input[data-testid=\\\"autocomplete-input\\\"]) > .formFieldName,\\n.contactPane :not(.choiceBox):has(> .formFieldValue input[data-testid=\\\"autocomplete-input\\\"]) > .formFieldName {\\n padding-top: var(--spacing-xs) !important;\\n}\\n\\n.individualPane .formFieldValue:has(input[data-testid=\\\"autocomplete-input\\\"]),\\n.contactPane .formFieldValue:has(input[data-testid=\\\"autocomplete-input\\\"]) {\\n align-self: flex-start;\\n}\\n\\n.individualPane .formFieldValue table[data-testid=\\\"autocomplete-table\\\"],\\n.contactPane .formFieldValue table[data-testid=\\\"autocomplete-table\\\"],\\n.individualPane .formFieldValue input[data-testid=\\\"autocomplete-input\\\"],\\n.contactPane .formFieldValue input[data-testid=\\\"autocomplete-input\\\"] {\\n margin: 0 !important;\\n}\\n\\n.individualPane .formFieldValue table[data-testid=\\\"autocomplete-table\\\"],\\n.contactPane .formFieldValue table[data-testid=\\\"autocomplete-table\\\"] {\\n vertical-align: baseline;\\n}\\n\\n.individualPane input:disabled,\\n.contactPane input:disabled,\\n.individualPane textarea:disabled,\\n.contactPane textarea:disabled,\\n.individualPane select:disabled,\\n.contactPane select:disabled,\\n.individualPane input[readonly],\\n.contactPane input[readonly],\\n.individualPane textarea[readonly],\\n.contactPane textarea[readonly],\\n.individualPane input:read-only,\\n.contactPane input:read-only,\\n.individualPane textarea:read-only,\\n.contactPane textarea:read-only {\\n background-color: var(--color-background) !important;\\n cursor: not-allowed;\\n opacity: var(--opacity-input-disabled);\\n border: var(--border-width-xthin) solid var(--color-background) !important;\\n}\\n\\n.contactPane .webidControl table td div.contactPane.namedPane {\\n border: none !important;\\n}\\n\\n/* ------------------------------------------------------------------ */\\n/* inline popup used for small confirmation flows (like the new confirmDialog) */\\n/* apply the class `rdf-inline-modal` on the outer wrapper and give the\\n inner box the class `popup` instead of using the old inline styles. */\\n\\n/* selectors that match the old inline-styled markup when no classes can be added */\\n\\n/* Delete pop up */\\n/* Remove the intermediate positioned ancestor so the popup anchors to .hoverControl instead */\\n.individualPane div[style*=\\\"position: relative\\\"]:has(> div[style*=\\\"display: grid\\\"]) {\\n position: static !important;\\n}\\n\\n.individualPane div[style*=\\\"position: relative\\\"] > div[style*=\\\"display: grid\\\"] {\\n /* override inline values with theme variables */\\n position: absolute !important;\\n top: 0 !important;\\n right: 0 !important;\\n left: auto !important;\\n z-index: 9999 !important;\\n display: grid !important;\\n pointer-events: auto !important;\\n opacity: 1 !important;\\n visibility: visible !important;\\n padding: var(--spacing-btn) !important;\\n background: var(--color-background) !important;\\n border: var(--border-width-sm) solid var(--color-primary) !important;\\n border-radius: var(--border-radius-base) !important;\\n box-shadow: var(--box-shadow-popup) !important;\\n grid-template-columns: auto auto !important;\\n gap: var(--spacing-xxs) !important;\\n}\\n\\n.individualPane .hoverControl img.hoverControlHide,\\n.individualPane .hoverControl [data-testid=\\\"deleteButtonWithCheck\\\"] {\\n position: absolute !important;\\n right: var(--spacing-xxxs) !important;\\n width: var(--icon-xs, 1.5rem) !important;\\n height: var(--icon-xs, 1.5rem) !important;\\n display: none !important;\\n align-items: center;\\n justify-content: center;\\n margin: 0 !important;\\n float: none !important;\\n z-index: 2 !important;\\n}\\n\\n/* Show delete icon only on hover */\\n.individualPane .hoverControl:hover img.hoverControlHide,\\n.individualPane .hoverControl:hover [data-testid=\\\"deleteButtonWithCheck\\\"] {\\n display: inline-flex !important;\\n}\\n\\n/* If the hoverControl has exactly one div + the delete icon, keep the icon vertically centered but right-aligned */\\n.individualPane .hoverControl:has(> div:nth-child(1):nth-last-child(2)):hover > img.hoverControlHide,\\n.individualPane .hoverControl:has(> div:nth-child(1):nth-last-child(2)):hover > [data-testid=\\\"deleteButtonWithCheck\\\"] {\\n top: 50% !important;\\n right: var(--spacing-xxxs) !important;\\n left: auto !important;\\n transform: translateY(-50%) !important;\\n}\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* ── Group Membership Section ──────────────────────────────── */\n\n.contactPane .group-membership-container {\n padding: var(--spacing-sm) 0;\n}\n\n/* Grid wrapper — matches detailsSectionContent groupButtonsList */\n.contactPane .group-pills-wrapper {\n display: grid !important;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)) !important;\n gap: var(--spacing-sm) !important;\n list-style: none;\n padding: 0;\n margin: 0;\n width: 100% !important;\n}\n\n.contactPane .group-pills-wrapper span {\n width: max-content !important;\n}\n\n/* Each group item: button on top, toolbar below */\n.contactPane .group-membership-item {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n max-width: 16rem; /* 256px */\n}\n\n.contactPane .group-membership-item > button {\n width: 100%;\n text-align: center;\n border-radius: var(--border-radius-base);\n word-wrap: break-word;\n overflow-wrap: break-word;\n min-height: var(--min-touch-target);\n}\n\n/* Toolbar with link icon and delete button below each group button */\n.contactPane .group-membership-item .group-membership-toolbar {\n display: flex;\n align-items: center;\n gap: var(--spacing-xs);\n padding: var(--spacing-xs) 0 0 0;\n}\n\n.contactPane .group-membership-item .group-membership-toolbar a {\n margin: 0.3rem;\n margin-left: 1rem;\n}\n\n.contactPane .group-membership-item .group-membership-toolbar a img {\n width: 1.3rem;\n height: 1rem;\n margin: 0;\n}\n\n/* Cancel float:right and any absolute positioning injected by solid-ui */\n.contactPane .group-membership-item .group-membership-toolbar > img.hoverControlHide,\n.contactPane .group-membership-item .group-membership-toolbar > [data-testid=\"deleteButtonWithCheck\"] {\n float: none !important;\n display: inline-flex !important;\n visibility: hidden !important;\n margin: 0 !important;\n}\n\n.contactPane .group-membership-item .group-membership-toolbar:hover > img.hoverControlHide,\n.contactPane .group-membership-item .group-membership-toolbar:hover > [data-testid=\"deleteButtonWithCheck\"] {\n visibility: visible !important;\n}\n\n.contactPane .detailsSectionContent .group-membership-item .group-membership-toolbar > div[style*=\"position: relative\"] {\n position: absolute !important;\n top: 0 !important;\n left: 50% !important;\n transform: translateX(-50%) !important;\n width: min(90vw, 27.5rem) !important; /* 440px */\n min-width: 17.5rem !important; /* 280px */\n max-width: 90vw !important;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n}\n\n.contactPane .detailsSectionContent .group-membership-item .group-membership-toolbar > div[style*=\"position: relative\"] > div {\n position: relative !important;\n top: auto !important;\n min-width: 17.5rem !important; /* 280px */ \n background: var(--color-background);\n border-radius: var(--border-radius-full);\n padding: var(--spacing-lg);\n box-shadow: var(--box-shadow-overlay);\n z-index: 1001;\n}\n\n@media (max-width: 599px) {\n .contactPane .group-membership-item .group-pills-wrapper {\n grid-template-columns: repeat(2, 1fr) !important;\n gap: var(--spacing-xs) !important;\n max-width: 100% !important;\n }\n\n .contactPane .group-membership-item .group-membership-item > button {\n font-size: var(--font-size-sm) !important;\n border-radius: var(--border-radius-base) !important;\n }\n}\n\n@media (min-width: 900px) {\n .contactPane .group-membership-item .group-pills-wrapper {\n grid-template-columns: repeat(3, 1fr) !important;\n gap: var(--spacing-sm) !important;\n }\n}\n`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/groupMembership.css\"],\"names\":[],\"mappings\":\"AAAA,iEAAiE;;AAEjE;EACE,4BAA4B;AAC9B;;AAEA,kEAAkE;AAClE;EACE,wBAAwB;EACxB,sEAAsE;EACtE,iCAAiC;EACjC,gBAAgB;EAChB,UAAU;EACV,SAAS;EACT,sBAAsB;AACxB;;AAEA;EACE,6BAA6B;AAC/B;;AAEA,kDAAkD;AAClD;EACE,aAAa;EACb,sBAAsB;EACtB,oBAAoB;EACpB,gBAAgB,EAAE,UAAU;AAC9B;;AAEA;EACE,WAAW;EACX,kBAAkB;EAClB,wCAAwC;EACxC,qBAAqB;EACrB,yBAAyB;EACzB,mCAAmC;AACrC;;AAEA,qEAAqE;AACrE;EACE,aAAa;EACb,mBAAmB;EACnB,sBAAsB;EACtB,gCAAgC;AAClC;;AAEA;EACE,cAAc;EACd,iBAAiB;AACnB;;AAEA;EACE,aAAa;EACb,YAAY;EACZ,SAAS;AACX;;AAEA,yEAAyE;AACzE;;EAEE,sBAAsB;EACtB,+BAA+B;EAC/B,6BAA6B;EAC7B,oBAAoB;AACtB;;AAEA;;EAEE,8BAA8B;AAChC;;AAEA;EACE,6BAA6B;EAC7B,iBAAiB;EACjB,oBAAoB;EACpB,sCAAsC;EACtC,oCAAoC,EAAE,UAAU;EAChD,6BAA6B,EAAE,UAAU;EACzC,0BAA0B;EAC1B,aAAa;EACb,mBAAmB;EACnB,uBAAuB;EACvB,aAAa;AACf;;AAEA;EACE,6BAA6B;EAC7B,oBAAoB;EACpB,6BAA6B,EAAE,UAAU;EACzC,mCAAmC;EACnC,wCAAwC;EACxC,0BAA0B;EAC1B,qCAAqC;EACrC,aAAa;AACf;;AAEA;EACE;IACE,gDAAgD;IAChD,iCAAiC;IACjC,0BAA0B;EAC5B;;EAEA;IACE,yCAAyC;IACzC,mDAAmD;EACrD;AACF;;AAEA;EACE;IACE,gDAAgD;IAChD,iCAAiC;EACnC;AACF\",\"sourcesContent\":[\"/* ── Group Membership Section ──────────────────────────────── */\\n\\n.contactPane .group-membership-container {\\n padding: var(--spacing-sm) 0;\\n}\\n\\n/* Grid wrapper — matches detailsSectionContent groupButtonsList */\\n.contactPane .group-pills-wrapper {\\n display: grid !important;\\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)) !important;\\n gap: var(--spacing-sm) !important;\\n list-style: none;\\n padding: 0;\\n margin: 0;\\n width: 100% !important;\\n}\\n\\n.contactPane .group-pills-wrapper span {\\n width: max-content !important;\\n}\\n\\n/* Each group item: button on top, toolbar below */\\n.contactPane .group-membership-item {\\n display: flex;\\n flex-direction: column;\\n align-items: stretch;\\n max-width: 16rem; /* 256px */\\n}\\n\\n.contactPane .group-membership-item > button {\\n width: 100%;\\n text-align: center;\\n border-radius: var(--border-radius-base);\\n word-wrap: break-word;\\n overflow-wrap: break-word;\\n min-height: var(--min-touch-target);\\n}\\n\\n/* Toolbar with link icon and delete button below each group button */\\n.contactPane .group-membership-item .group-membership-toolbar {\\n display: flex;\\n align-items: center;\\n gap: var(--spacing-xs);\\n padding: var(--spacing-xs) 0 0 0;\\n}\\n\\n.contactPane .group-membership-item .group-membership-toolbar a {\\n margin: 0.3rem;\\n margin-left: 1rem;\\n}\\n\\n.contactPane .group-membership-item .group-membership-toolbar a img {\\n width: 1.3rem;\\n height: 1rem;\\n margin: 0;\\n}\\n\\n/* Cancel float:right and any absolute positioning injected by solid-ui */\\n.contactPane .group-membership-item .group-membership-toolbar > img.hoverControlHide,\\n.contactPane .group-membership-item .group-membership-toolbar > [data-testid=\\\"deleteButtonWithCheck\\\"] {\\n float: none !important;\\n display: inline-flex !important;\\n visibility: hidden !important;\\n margin: 0 !important;\\n}\\n\\n.contactPane .group-membership-item .group-membership-toolbar:hover > img.hoverControlHide,\\n.contactPane .group-membership-item .group-membership-toolbar:hover > [data-testid=\\\"deleteButtonWithCheck\\\"] {\\n visibility: visible !important;\\n}\\n\\n.contactPane .detailsSectionContent .group-membership-item .group-membership-toolbar > div[style*=\\\"position: relative\\\"] {\\n position: absolute !important;\\n top: 0 !important;\\n left: 50% !important;\\n transform: translateX(-50%) !important;\\n width: min(90vw, 27.5rem) !important; /* 440px */\\n min-width: 17.5rem !important; /* 280px */\\n max-width: 90vw !important;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n z-index: 1000;\\n}\\n\\n.contactPane .detailsSectionContent .group-membership-item .group-membership-toolbar > div[style*=\\\"position: relative\\\"] > div {\\n position: relative !important;\\n top: auto !important;\\n min-width: 17.5rem !important; /* 280px */ \\n background: var(--color-background);\\n border-radius: var(--border-radius-full);\\n padding: var(--spacing-lg);\\n box-shadow: var(--box-shadow-overlay);\\n z-index: 1001;\\n}\\n\\n@media (max-width: 599px) {\\n .contactPane .group-membership-item .group-pills-wrapper {\\n grid-template-columns: repeat(2, 1fr) !important;\\n gap: var(--spacing-xs) !important;\\n max-width: 100% !important;\\n }\\n\\n .contactPane .group-membership-item .group-membership-item > button {\\n font-size: var(--font-size-sm) !important;\\n border-radius: var(--border-radius-base) !important;\\n }\\n}\\n\\n@media (min-width: 900px) {\\n .contactPane .group-membership-item .group-pills-wrapper {\\n grid-template-columns: repeat(3, 1fr) !important;\\n gap: var(--spacing-sm) !important;\\n }\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* individual.js styles — extracted from inline styles */\n\n/* ── Individual pane container ───────────────────────────────── */\n\n.individualPane {\n padding: var(--spacing-xs) var(--spacing-lg) var(--spacing-md) var(--spacing-lg);\n background: var(--color-section-bg);\n border-radius: var(--border-radius-full);\n box-shadow: var(--box-shadow);\n box-sizing: border-box;\n max-width: 100%;\n}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/individual.css\"],\"names\":[],\"mappings\":\"AAAA,wDAAwD;;AAExD,mEAAmE;;AAEnE;EACE,gFAAgF;EAChF,mCAAmC;EACnC,wCAAwC;EACxC,6BAA6B;EAC7B,sBAAsB;EACtB,eAAe;AACjB\",\"sourcesContent\":[\"/* individual.js styles — extracted from inline styles */\\n\\n/* ── Individual pane container ───────────────────────────────── */\\n\\n.individualPane {\\n padding: var(--spacing-xs) var(--spacing-lg) var(--spacing-md) var(--spacing-lg);\\n background: var(--color-section-bg);\\n border-radius: var(--border-radius-full);\\n box-shadow: var(--box-shadow);\\n box-sizing: border-box;\\n max-width: 100%;\\n}\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* CSS for the accessible modal dialogs created by localUtils.js */\n\n/* backdrop / focus trap container */\n.focus-trap {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 9999;\n background: var(--overlay-bg);\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n/* inner dialog box */\n.focus-trap .modal {\n background: var(--color-background);\n padding: var(--spacing-lg);\n border-radius: var(--border-radius-base);\n max-width: 90%;\n box-shadow: var(--box-shadow-modal);\n}\n\n/* button container: center buttons horizontally (uses id in markup) */\n#contacts-modal #modal-buttons {\n margin-top: var(--spacing-md);\n display: flex;\n justify-content: center;\n gap: var(--spacing-sm);\n}\n\n/* buttons themselves use the shared btn-primary rules */\n#contacts-modal .modal button {\n min-height: var(--min-touch-target);\n padding: var(--spacing-sm) var(--spacing-md);\n border: 1px solid var(--color-primary);\n border-radius: var(--border-radius-base);\n font-weight: var(--font-weight-bold, 600);\n cursor: pointer;\n transition: all var(--animation-duration) ease;\n}\n\n#contacts-modal .modal button:disabled {\n opacity: var(--opacity-disabled);\n cursor: not-allowed;\n transform: none;\n}\n`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/localUtils.css\"],\"names\":[],\"mappings\":\"AAAA,kEAAkE;;AAElE,oCAAoC;AACpC;EACE,eAAe;EACf,MAAM;EACN,OAAO;EACP,WAAW;EACX,YAAY;EACZ,aAAa;EACb,6BAA6B;EAC7B,aAAa;EACb,uBAAuB;EACvB,mBAAmB;AACrB;;AAEA,qBAAqB;AACrB;EACE,mCAAmC;EACnC,0BAA0B;EAC1B,wCAAwC;EACxC,cAAc;EACd,mCAAmC;AACrC;;AAEA,sEAAsE;AACtE;EACE,6BAA6B;EAC7B,aAAa;EACb,uBAAuB;EACvB,sBAAsB;AACxB;;AAEA,wDAAwD;AACxD;EACE,mCAAmC;EACnC,4CAA4C;EAC5C,sCAAsC;EACtC,wCAAwC;EACxC,yCAAyC;EACzC,eAAe;EACf,8CAA8C;AAChD;;AAEA;EACE,gCAAgC;EAChC,mBAAmB;EACnB,eAAe;AACjB\",\"sourcesContent\":[\"/* CSS for the accessible modal dialogs created by localUtils.js */\\n\\n/* backdrop / focus trap container */\\n.focus-trap {\\n position: fixed;\\n top: 0;\\n left: 0;\\n width: 100%;\\n height: 100%;\\n z-index: 9999;\\n background: var(--overlay-bg);\\n display: flex;\\n justify-content: center;\\n align-items: center;\\n}\\n\\n/* inner dialog box */\\n.focus-trap .modal {\\n background: var(--color-background);\\n padding: var(--spacing-lg);\\n border-radius: var(--border-radius-base);\\n max-width: 90%;\\n box-shadow: var(--box-shadow-modal);\\n}\\n\\n/* button container: center buttons horizontally (uses id in markup) */\\n#contacts-modal #modal-buttons {\\n margin-top: var(--spacing-md);\\n display: flex;\\n justify-content: center;\\n gap: var(--spacing-sm);\\n}\\n\\n/* buttons themselves use the shared btn-primary rules */\\n#contacts-modal .modal button {\\n min-height: var(--min-touch-target);\\n padding: var(--spacing-sm) var(--spacing-md);\\n border: 1px solid var(--color-primary);\\n border-radius: var(--border-radius-base);\\n font-weight: var(--font-weight-bold, 600);\\n cursor: pointer;\\n transition: all var(--animation-duration) ease;\\n}\\n\\n#contacts-modal .modal button:disabled {\\n opacity: var(--opacity-disabled);\\n cursor: not-allowed;\\n transform: none;\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* mugshotGallery.js styles — extracted from inline styles */\n/* Uses CSS custom properties from the global stylesheet (dev-global.css / mashlib) */\n\n/* ── Mugshot image ───────────────────────────────────────────── */\n\n.contactPane .mugshotImage {\n max-height: 10rem;\n border-radius: var(--border-radius-full);\n margin: var(--spacing-sm);\n}\n\n.contactPane button:has(> img[src\\$=\".svg\"]) {\n background-color: var(--color-section-bg) !important;\n border: none !important;\n margin: 0 !important;\n border-radius: 0 !important;\n}\n`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/mugshotGallery.css\"],\"names\":[],\"mappings\":\"AAAA,4DAA4D;AAC5D,qFAAqF;;AAErF,mEAAmE;;AAEnE;EACE,iBAAiB;EACjB,wCAAwC;EACxC,yBAAyB;AAC3B;;AAEA;EACE,oDAAoD;EACpD,uBAAuB;EACvB,oBAAoB;EACpB,2BAA2B;AAC7B\",\"sourcesContent\":[\"/* mugshotGallery.js styles — extracted from inline styles */\\n/* Uses CSS custom properties from the global stylesheet (dev-global.css / mashlib) */\\n\\n/* ── Mugshot image ───────────────────────────────────────────── */\\n\\n.contactPane .mugshotImage {\\n max-height: 10rem;\\n border-radius: var(--border-radius-full);\\n margin: var(--spacing-sm);\\n}\\n\\n.contactPane button:has(> img[src$=\\\".svg\\\"]) {\\n background-color: var(--color-section-bg) !important;\\n border: none !important;\\n margin: 0 !important;\\n border-radius: 0 !important;\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* toolsPane.js styles — extracted from inline styles */\n/* Uses CSS custom properties from the global stylesheet (dev-global.css / mashlib) */\n\n/* ── Tools pane table ────────────────────────────────────────── */\n\n.contactPane .statsLog {\n font-size: var(--font-size-lg);\n margin: var(--spacing-md);\n background-color: var(--color-background);\n}\n\n.contactPane .statsLog pre {\n padding: var(--spacing-md);\n white-space: pre-wrap;\n word-wrap: break-word;\n overflow-wrap: break-word;\n overflow: hidden;\n max-width: 100%;\n}\n\n/* ── Tools pane layout ────────────────────────────────────────── */\n\n.contactPane .toolsPane {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-xs);\n}\n\n.contactPane .toolsButtonsContainer {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-xs);\n}\n\n/* ── Load index button states ──────────────────────────────── */\n\n.contactPane .toolsButton--error {\n background-color: var(--color-error);\n}\n\n.contactPane .toolsButton--success {\n background-color: var(--color-primary);\n}\n`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/toolsPane.css\"],\"names\":[],\"mappings\":\"AAAA,uDAAuD;AACvD,qFAAqF;;AAErF,mEAAmE;;AAEnE;EACE,8BAA8B;EAC9B,yBAAyB;EACzB,yCAAyC;AAC3C;;AAEA;EACE,0BAA0B;EAC1B,qBAAqB;EACrB,qBAAqB;EACrB,yBAAyB;EACzB,gBAAgB;EAChB,eAAe;AACjB;;AAEA,oEAAoE;;AAEpE;EACE,aAAa;EACb,sBAAsB;EACtB,sBAAsB;AACxB;;AAEA;EACE,aAAa;EACb,eAAe;EACf,sBAAsB;AACxB;;AAEA,iEAAiE;;AAEjE;EACE,oCAAoC;AACtC;;AAEA;EACE,sCAAsC;AACxC\",\"sourcesContent\":[\"/* toolsPane.js styles — extracted from inline styles */\\n/* Uses CSS custom properties from the global stylesheet (dev-global.css / mashlib) */\\n\\n/* ── Tools pane table ────────────────────────────────────────── */\\n\\n.contactPane .statsLog {\\n font-size: var(--font-size-lg);\\n margin: var(--spacing-md);\\n background-color: var(--color-background);\\n}\\n\\n.contactPane .statsLog pre {\\n padding: var(--spacing-md);\\n white-space: pre-wrap;\\n word-wrap: break-word;\\n overflow-wrap: break-word;\\n overflow: hidden;\\n max-width: 100%;\\n}\\n\\n/* ── Tools pane layout ────────────────────────────────────────── */\\n\\n.contactPane .toolsPane {\\n display: flex;\\n flex-direction: column;\\n gap: var(--spacing-xs);\\n}\\n\\n.contactPane .toolsButtonsContainer {\\n display: flex;\\n flex-wrap: wrap;\\n gap: var(--spacing-xs);\\n}\\n\\n/* ── Load index button states ──────────────────────────────── */\\n\\n.contactPane .toolsButton--error {\\n background-color: var(--color-error);\\n}\\n\\n.contactPane .toolsButton--success {\\n background-color: var(--color-primary);\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* Shared utility variables for component styles.\n These are kept here (instead of in dev-global.css) so they can be\n bundled with component styles and reused consistently across the app.\n*/\n\n/* Utility helper classes */\n\n/* different from mashlib .btn-primary:active {\n box-shadow: var(--box-shadow-active);\n} */\n`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/utilities.css\"],\"names\":[],\"mappings\":\"AAAA;;;CAGC;;AAED,2BAA2B;;AAE3B;;GAEG\",\"sourcesContent\":[\"/* Shared utility variables for component styles.\\n These are kept here (instead of in dev-global.css) so they can be\\n bundled with component styles and reused consistently across the app.\\n*/\\n\\n/* Utility helper classes */\\n\\n/* different from mashlib .btn-primary:active {\\n box-shadow: var(--box-shadow-active);\\n} */\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `/* ── Named pane (rendered sub-pane) ──────────────────────────── */\n.contactPane .namedPane {\n border: var(--border-width-sm) solid var(--color-text-muted);\n border-radius: var(--border-radius-base);\n}\n\n/* ── Persona row ─────────────────────────────────────────────── */\n\n.contactPane .personaRow {\n padding: var(--spacing-xs);\n}\n\n.contactPane .personaRow--webid,\n.contactPane .personaRow--webid td,\n.contactPane .personaRow--webid button,\n.contactPane .personaRow--webid button:hover,\n.contactPane .personaRow--webid .hoverControl:has(> img:first-child),\n.contactPane .personaRow--webid .hoverControl:has(> img:first-child):hover,\n.contactPane .personaRow--webid .personaOpenButton:has(> img:first-child),\n.contactPane .personaRow--webid .personaOpenButton:has(> img:first-child):hover {\n background-color: var(--color-info-bg) !important;\n}\n\n/* ── Full-width elements ─────────────────────────────────────── */\n\n.contactPane .fullWidth {\n width: 100%;\n}\n\n/* ── Open/close profile button ───────────────────────────────── */\n\n.contactPane .personaOpenButton {\n float: right;\n background-color: transparent;\n border: none;\n}\n\n/* hoverControl layout overrides are now enforced in contactsRDFFormsEnforced.css */\n\n/* ── Delete confirmation popup in webidControl ───────────────── */\n\n/* Remove intermediate positioned ancestor so popup anchors to .hoverControl */\n.contactPane .webidControl div[style*=\"position: relative\"]:has(> div[style*=\"display: grid\"]) {\n position: static !important;\n}\n\n/* Position the popup absolutely so it never participates in the flex row */\n.contactPane .webidControl div[style*=\"position: relative\"] > div[style*=\"display: grid\"] {\n position: absolute !important;\n top: 0 !important;\n right: 0 !important;\n left: auto !important;\n z-index: 9999 !important;\n display: grid !important;\n pointer-events: auto !important;\n opacity: 1 !important;\n visibility: visible !important;\n padding: var(--spacing-btn) !important;\n min-width: 12em !important;\n background: var(--color-background) !important;\n border: var(--border-width-sm) solid var(--color-primary) !important;\n border-radius: var(--border-radius-base) !important;\n box-shadow: var(--box-shadow-popup) !important;\n grid-template-columns: auto auto !important;\n gap: var(--spacing-xxs) !important;\n}\n\n/* ── Section heading ─────────────────────────────────────────── */\n\n.contactPane .contactPanedHeading {\n font-size: var(--font-size-lg);\n font-weight: bold;\n color: var(--color-primary);\n margin: var(--spacing-sm) 0;\n}\n\n/* ── Prompt text ─────────────────────────────────────────────── */\n\n.contactPane .webidPrompt {\n padding: var(--spacing-sm);\n border: none;\n font-size: var(--font-size-base);\n white-space: pre-wrap;\n}\n\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane,\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) table td div.contactPane.namedPane {\n display: block;\n width: 100% !important;\n max-width: none !important;\n min-width: 0 !important;\n box-sizing: border-box;\n container-type: inline-size;\n container-name: nested-profile-pane;\n margin-top: var(--spacing-sm);\n}\n\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profile-grid,\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane #main-content.profile-grid {\n display: flex !important;\n flex-direction: column !important;\n gap: var(--spacing-sm) !important;\n}\n\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profile__main,\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profile__sidebar,\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profile__section {\n width: 100% !important;\n min-width: 0 !important;\n max-width: 100% !important;\n box-sizing: border-box;\n overflow-wrap: anywhere;\n}\n\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profile__sidebar,\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profile__section,\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profile__main {\n padding: var(--spacing-sm) !important;\n}\n\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profileSectionCollapsible[data-expanded=\"false\"] .profileSectionCollapsible__content {\n display: none !important;\n}\n\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profileSectionCollapsible__toggle {\n display: inline-flex !important;\n align-items: center;\n justify-content: center;\n min-height: auto !important;\n min-width: auto !important;\n padding: var(--spacing-xxs) !important;\n border: none !important;\n background: none !important;\n color: var(--color-text) !important;\n}\n\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profileSectionCollapsible[data-expanded=\"true\"] .profileSectionCollapsible__chevron {\n transform: rotate(180deg);\n}\n\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profileSectionCollapsible__editLabel {\n display: none !important;\n}\n\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profileSectionCollapsible__editIcon {\n display: inline !important;\n}\n\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .socialItem {\n display: flex !important;\n align-items: center !important;\n flex: 0 0 auto !important;\n}\n\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .socialItem a {\n display: inline-flex !important;\n align-items: center !important;\n justify-content: center !important;\n flex: 0 0 auto !important;\n width: auto !important;\n min-width: var(--min-touch-target) !important;\n min-height: var(--min-touch-target) !important;\n line-height: 0 !important;\n}\n\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .socialIcon {\n display: block !important;\n width: 40px !important;\n height: 40px !important;\n min-width: 40px !important;\n min-height: 40px !important;\n max-width: 40px !important;\n max-height: 40px !important;\n object-fit: contain !important;\n flex-shrink: 0 !important;\n}\n\n@media (max-width: 1000px) {\n .contactPane .webidControl,\n .contactPane .webidControl table,\n .contactPane .webidControl tbody,\n .contactPane .webidControl tr,\n .contactPane .webidControl td {\n width: 100%;\n max-width: 100%;\n min-width: 0;\n box-sizing: border-box;\n }\n\n .contactPane .webidControl table {\n table-layout: fixed;\n }\n\n .contactPane .webidControl .personaRow--webid td {\n vertical-align: top;\n }\n\n .contactPane .webidControl .contactPane,\n .contactPane .webidControl .contactPane .addressBook-grid,\n .contactPane .webidControl .contactPane .detailSection,\n .contactPane .webidControl .contactPane .detailsSectionContent {\n width: 100% !important;\n max-width: 100% !important;\n min-width: 0 !important;\n box-sizing: border-box;\n }\n\n .contactPane .webidControl .contactPane .addressBook-grid {\n flex-direction: column !important;\n flex-wrap: nowrap !important;\n }\n\n .contactPane .webidControl .contactPane .detailSection,\n .contactPane .webidControl .contactPane .addressBookSection {\n flex: none !important;\n }\n\n .contactPane .webidControl .contactPane .detailsSectionContent,\n .contactPane .webidControl .contactPane .detailsSectionContent--wide {\n padding: var(--spacing-sm) !important;\n overflow-y: visible !important;\n }\n\n}\n\n@container nested-profile-pane (max-width: 900px) {\n .contactPane .webidControl .profile-grid {\n display: flex !important;\n flex-direction: column !important;\n gap: var(--spacing-sm) !important;\n }\n\n .contactPane .webidControl .profile-grid > * {\n min-width: 0 !important;\n max-width: 100% !important;\n }\n\n .contactPane .webidControl .profile__main,\n .contactPane .webidControl .profile__sidebar,\n .contactPane .webidControl .profile__section {\n width: 100% !important;\n min-width: 0 !important;\n max-width: 100% !important;\n overflow-wrap: anywhere;\n }\n}\n\n/* ── Visibility / display helpers ────────────────────────────── */\n\n.contactPane .collapsed {\n visibility: collapse;\n}\n`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/styles/webidControl.css\"],\"names\":[],\"mappings\":\"AAAA,mEAAmE;AACnE;EACE,4DAA4D;EAC5D,wCAAwC;AAC1C;;AAEA,mEAAmE;;AAEnE;EACE,0BAA0B;AAC5B;;AAEA;;;;;;;;EAQE,iDAAiD;AACnD;;AAEA,mEAAmE;;AAEnE;EACE,WAAW;AACb;;AAEA,mEAAmE;;AAEnE;EACE,YAAY;EACZ,6BAA6B;EAC7B,YAAY;AACd;;AAEA,mFAAmF;;AAEnF,mEAAmE;;AAEnE,8EAA8E;AAC9E;EACE,2BAA2B;AAC7B;;AAEA,2EAA2E;AAC3E;EACE,6BAA6B;EAC7B,iBAAiB;EACjB,mBAAmB;EACnB,qBAAqB;EACrB,wBAAwB;EACxB,wBAAwB;EACxB,+BAA+B;EAC/B,qBAAqB;EACrB,8BAA8B;EAC9B,sCAAsC;EACtC,0BAA0B;EAC1B,8CAA8C;EAC9C,oEAAoE;EACpE,mDAAmD;EACnD,8CAA8C;EAC9C,2CAA2C;EAC3C,kCAAkC;AACpC;;AAEA,mEAAmE;;AAEnE;EACE,8BAA8B;EAC9B,iBAAiB;EACjB,2BAA2B;EAC3B,2BAA2B;AAC7B;;AAEA,mEAAmE;;AAEnE;EACE,0BAA0B;EAC1B,YAAY;EACZ,gCAAgC;EAChC,qBAAqB;AACvB;;AAEA;;EAEE,cAAc;EACd,sBAAsB;EACtB,0BAA0B;EAC1B,uBAAuB;EACvB,sBAAsB;EACtB,2BAA2B;EAC3B,mCAAmC;EACnC,6BAA6B;AAC/B;;AAEA;;EAEE,wBAAwB;EACxB,iCAAiC;EACjC,iCAAiC;AACnC;;AAEA;;;EAGE,sBAAsB;EACtB,uBAAuB;EACvB,0BAA0B;EAC1B,sBAAsB;EACtB,uBAAuB;AACzB;;AAEA;;;EAGE,qCAAqC;AACvC;;AAEA;EACE,wBAAwB;AAC1B;;AAEA;EACE,+BAA+B;EAC/B,mBAAmB;EACnB,uBAAuB;EACvB,2BAA2B;EAC3B,0BAA0B;EAC1B,sCAAsC;EACtC,uBAAuB;EACvB,2BAA2B;EAC3B,mCAAmC;AACrC;;AAEA;EACE,yBAAyB;AAC3B;;AAEA;EACE,wBAAwB;AAC1B;;AAEA;EACE,0BAA0B;AAC5B;;AAEA;EACE,wBAAwB;EACxB,8BAA8B;EAC9B,yBAAyB;AAC3B;;AAEA;EACE,+BAA+B;EAC/B,8BAA8B;EAC9B,kCAAkC;EAClC,yBAAyB;EACzB,sBAAsB;EACtB,6CAA6C;EAC7C,8CAA8C;EAC9C,yBAAyB;AAC3B;;AAEA;EACE,yBAAyB;EACzB,sBAAsB;EACtB,uBAAuB;EACvB,0BAA0B;EAC1B,2BAA2B;EAC3B,0BAA0B;EAC1B,2BAA2B;EAC3B,8BAA8B;EAC9B,yBAAyB;AAC3B;;AAEA;EACE;;;;;IAKE,WAAW;IACX,eAAe;IACf,YAAY;IACZ,sBAAsB;EACxB;;EAEA;IACE,mBAAmB;EACrB;;EAEA;IACE,mBAAmB;EACrB;;EAEA;;;;IAIE,sBAAsB;IACtB,0BAA0B;IAC1B,uBAAuB;IACvB,sBAAsB;EACxB;;EAEA;IACE,iCAAiC;IACjC,4BAA4B;EAC9B;;EAEA;;IAEE,qBAAqB;EACvB;;EAEA;;IAEE,qCAAqC;IACrC,8BAA8B;EAChC;;AAEF;;AAEA;EACE;IACE,wBAAwB;IACxB,iCAAiC;IACjC,iCAAiC;EACnC;;EAEA;IACE,uBAAuB;IACvB,0BAA0B;EAC5B;;EAEA;;;IAGE,sBAAsB;IACtB,uBAAuB;IACvB,0BAA0B;IAC1B,uBAAuB;EACzB;AACF;;AAEA,mEAAmE;;AAEnE;EACE,oBAAoB;AACtB\",\"sourcesContent\":[\"/* ── Named pane (rendered sub-pane) ──────────────────────────── */\\n.contactPane .namedPane {\\n border: var(--border-width-sm) solid var(--color-text-muted);\\n border-radius: var(--border-radius-base);\\n}\\n\\n/* ── Persona row ─────────────────────────────────────────────── */\\n\\n.contactPane .personaRow {\\n padding: var(--spacing-xs);\\n}\\n\\n.contactPane .personaRow--webid,\\n.contactPane .personaRow--webid td,\\n.contactPane .personaRow--webid button,\\n.contactPane .personaRow--webid button:hover,\\n.contactPane .personaRow--webid .hoverControl:has(> img:first-child),\\n.contactPane .personaRow--webid .hoverControl:has(> img:first-child):hover,\\n.contactPane .personaRow--webid .personaOpenButton:has(> img:first-child),\\n.contactPane .personaRow--webid .personaOpenButton:has(> img:first-child):hover {\\n background-color: var(--color-info-bg) !important;\\n}\\n\\n/* ── Full-width elements ─────────────────────────────────────── */\\n\\n.contactPane .fullWidth {\\n width: 100%;\\n}\\n\\n/* ── Open/close profile button ───────────────────────────────── */\\n\\n.contactPane .personaOpenButton {\\n float: right;\\n background-color: transparent;\\n border: none;\\n}\\n\\n/* hoverControl layout overrides are now enforced in contactsRDFFormsEnforced.css */\\n\\n/* ── Delete confirmation popup in webidControl ───────────────── */\\n\\n/* Remove intermediate positioned ancestor so popup anchors to .hoverControl */\\n.contactPane .webidControl div[style*=\\\"position: relative\\\"]:has(> div[style*=\\\"display: grid\\\"]) {\\n position: static !important;\\n}\\n\\n/* Position the popup absolutely so it never participates in the flex row */\\n.contactPane .webidControl div[style*=\\\"position: relative\\\"] > div[style*=\\\"display: grid\\\"] {\\n position: absolute !important;\\n top: 0 !important;\\n right: 0 !important;\\n left: auto !important;\\n z-index: 9999 !important;\\n display: grid !important;\\n pointer-events: auto !important;\\n opacity: 1 !important;\\n visibility: visible !important;\\n padding: var(--spacing-btn) !important;\\n min-width: 12em !important;\\n background: var(--color-background) !important;\\n border: var(--border-width-sm) solid var(--color-primary) !important;\\n border-radius: var(--border-radius-base) !important;\\n box-shadow: var(--box-shadow-popup) !important;\\n grid-template-columns: auto auto !important;\\n gap: var(--spacing-xxs) !important;\\n}\\n\\n/* ── Section heading ─────────────────────────────────────────── */\\n\\n.contactPane .contactPanedHeading {\\n font-size: var(--font-size-lg);\\n font-weight: bold;\\n color: var(--color-primary);\\n margin: var(--spacing-sm) 0;\\n}\\n\\n/* ── Prompt text ─────────────────────────────────────────────── */\\n\\n.contactPane .webidPrompt {\\n padding: var(--spacing-sm);\\n border: none;\\n font-size: var(--font-size-base);\\n white-space: pre-wrap;\\n}\\n\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane,\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) table td div.contactPane.namedPane {\\n display: block;\\n width: 100% !important;\\n max-width: none !important;\\n min-width: 0 !important;\\n box-sizing: border-box;\\n container-type: inline-size;\\n container-name: nested-profile-pane;\\n margin-top: var(--spacing-sm);\\n}\\n\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profile-grid,\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane #main-content.profile-grid {\\n display: flex !important;\\n flex-direction: column !important;\\n gap: var(--spacing-sm) !important;\\n}\\n\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profile__main,\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profile__sidebar,\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profile__section {\\n width: 100% !important;\\n min-width: 0 !important;\\n max-width: 100% !important;\\n box-sizing: border-box;\\n overflow-wrap: anywhere;\\n}\\n\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profile__sidebar,\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profile__section,\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profile__main {\\n padding: var(--spacing-sm) !important;\\n}\\n\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profileSectionCollapsible[data-expanded=\\\"false\\\"] .profileSectionCollapsible__content {\\n display: none !important;\\n}\\n\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profileSectionCollapsible__toggle {\\n display: inline-flex !important;\\n align-items: center;\\n justify-content: center;\\n min-height: auto !important;\\n min-width: auto !important;\\n padding: var(--spacing-xxs) !important;\\n border: none !important;\\n background: none !important;\\n color: var(--color-text) !important;\\n}\\n\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profileSectionCollapsible[data-expanded=\\\"true\\\"] .profileSectionCollapsible__chevron {\\n transform: rotate(180deg);\\n}\\n\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profileSectionCollapsible__editLabel {\\n display: none !important;\\n}\\n\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .profileSectionCollapsible__editIcon {\\n display: inline !important;\\n}\\n\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .socialItem {\\n display: flex !important;\\n align-items: center !important;\\n flex: 0 0 auto !important;\\n}\\n\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .socialItem a {\\n display: inline-flex !important;\\n align-items: center !important;\\n justify-content: center !important;\\n flex: 0 0 auto !important;\\n width: auto !important;\\n min-width: var(--min-touch-target) !important;\\n min-height: var(--min-touch-target) !important;\\n line-height: 0 !important;\\n}\\n\\n.contactPane :is(.contactPane--narrow .webidControl, .webidControl.webidControl--mobile) .namedPane .socialIcon {\\n display: block !important;\\n width: 40px !important;\\n height: 40px !important;\\n min-width: 40px !important;\\n min-height: 40px !important;\\n max-width: 40px !important;\\n max-height: 40px !important;\\n object-fit: contain !important;\\n flex-shrink: 0 !important;\\n}\\n\\n@media (max-width: 1000px) {\\n .contactPane .webidControl,\\n .contactPane .webidControl table,\\n .contactPane .webidControl tbody,\\n .contactPane .webidControl tr,\\n .contactPane .webidControl td {\\n width: 100%;\\n max-width: 100%;\\n min-width: 0;\\n box-sizing: border-box;\\n }\\n\\n .contactPane .webidControl table {\\n table-layout: fixed;\\n }\\n\\n .contactPane .webidControl .personaRow--webid td {\\n vertical-align: top;\\n }\\n\\n .contactPane .webidControl .contactPane,\\n .contactPane .webidControl .contactPane .addressBook-grid,\\n .contactPane .webidControl .contactPane .detailSection,\\n .contactPane .webidControl .contactPane .detailsSectionContent {\\n width: 100% !important;\\n max-width: 100% !important;\\n min-width: 0 !important;\\n box-sizing: border-box;\\n }\\n\\n .contactPane .webidControl .contactPane .addressBook-grid {\\n flex-direction: column !important;\\n flex-wrap: nowrap !important;\\n }\\n\\n .contactPane .webidControl .contactPane .detailSection,\\n .contactPane .webidControl .contactPane .addressBookSection {\\n flex: none !important;\\n }\\n\\n .contactPane .webidControl .contactPane .detailsSectionContent,\\n .contactPane .webidControl .contactPane .detailsSectionContent--wide {\\n padding: var(--spacing-sm) !important;\\n overflow-y: visible !important;\\n }\\n\\n}\\n\\n@container nested-profile-pane (max-width: 900px) {\\n .contactPane .webidControl .profile-grid {\\n display: flex !important;\\n flex-direction: column !important;\\n gap: var(--spacing-sm) !important;\\n }\\n\\n .contactPane .webidControl .profile-grid > * {\\n min-width: 0 !important;\\n max-width: 100% !important;\\n }\\n\\n .contactPane .webidControl .profile__main,\\n .contactPane .webidControl .profile__sidebar,\\n .contactPane .webidControl .profile__section {\\n width: 100% !important;\\n min-width: 0 !important;\\n max-width: 100% !important;\\n overflow-wrap: anywhere;\\n }\\n}\\n\\n/* ── Visibility / display helpers ────────────────────────────── */\\n\\n.contactPane .collapsed {\\n visibility: collapse;\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","\"use strict\";\n\n/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n*/\nmodule.exports = function (cssWithMappingToString) {\n var list = [];\n\n // return the list of modules as css string\n list.toString = function toString() {\n return this.map(function (item) {\n var content = \"\";\n var needLayer = typeof item[5] !== \"undefined\";\n if (item[4]) {\n content += \"@supports (\".concat(item[4], \") {\");\n }\n if (item[2]) {\n content += \"@media \".concat(item[2], \" {\");\n }\n if (needLayer) {\n content += \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\");\n }\n content += cssWithMappingToString(item);\n if (needLayer) {\n content += \"}\";\n }\n if (item[2]) {\n content += \"}\";\n }\n if (item[4]) {\n content += \"}\";\n }\n return content;\n }).join(\"\");\n };\n\n // import a list of modules into the list\n list.i = function i(modules, media, dedupe, supports, layer) {\n if (typeof modules === \"string\") {\n modules = [[null, modules, undefined]];\n }\n var alreadyImportedModules = {};\n if (dedupe) {\n for (var k = 0; k < this.length; k++) {\n var id = this[k][0];\n if (id != null) {\n alreadyImportedModules[id] = true;\n }\n }\n }\n for (var _k = 0; _k < modules.length; _k++) {\n var item = [].concat(modules[_k]);\n if (dedupe && alreadyImportedModules[item[0]]) {\n continue;\n }\n if (typeof layer !== \"undefined\") {\n if (typeof item[5] === \"undefined\") {\n item[5] = layer;\n } else {\n item[1] = \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\").concat(item[1], \"}\");\n item[5] = layer;\n }\n }\n if (media) {\n if (!item[2]) {\n item[2] = media;\n } else {\n item[1] = \"@media \".concat(item[2], \" {\").concat(item[1], \"}\");\n item[2] = media;\n }\n }\n if (supports) {\n if (!item[4]) {\n item[4] = \"\".concat(supports);\n } else {\n item[1] = \"@supports (\".concat(item[4], \") {\").concat(item[1], \"}\");\n item[4] = supports;\n }\n }\n list.push(item);\n }\n };\n return list;\n};","\"use strict\";\n\nmodule.exports = function (url, options) {\n if (!options) {\n options = {};\n }\n if (!url) {\n return url;\n }\n url = String(url.__esModule ? url.default : url);\n\n // If url is already wrapped in quotes, remove them\n if (/^['\"].*['\"]$/.test(url)) {\n url = url.slice(1, -1);\n }\n if (options.hash) {\n url += options.hash;\n }\n\n // Should url be wrapped?\n // See https://drafts.csswg.org/css-values-3/#urls\n if (/[\"'() \\t\\n]|(%20)/.test(url) || options.needQuotes) {\n return \"\\\"\".concat(url.replace(/\"/g, '\\\\\"').replace(/\\n/g, \"\\\\n\"), \"\\\"\");\n }\n return url;\n};","\"use strict\";\n\nmodule.exports = function (item) {\n var content = item[1];\n var cssMapping = item[3];\n if (!cssMapping) {\n return content;\n }\n if (typeof btoa === \"function\") {\n var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(cssMapping))));\n var data = \"sourceMappingURL=data:application/json;charset=utf-8;base64,\".concat(base64);\n var sourceMapping = \"/*# \".concat(data, \" */\");\n return [content].concat([sourceMapping]).join(\"\\n\");\n }\n return [content].join(\"\\n\");\n};","\"use strict\";\n\nvar stylesInDOM = [];\nfunction getIndexByIdentifier(identifier) {\n var result = -1;\n for (var i = 0; i < stylesInDOM.length; i++) {\n if (stylesInDOM[i].identifier === identifier) {\n result = i;\n break;\n }\n }\n return result;\n}\nfunction modulesToDom(list, options) {\n var idCountMap = {};\n var identifiers = [];\n for (var i = 0; i < list.length; i++) {\n var item = list[i];\n var id = options.base ? item[0] + options.base : item[0];\n var count = idCountMap[id] || 0;\n var identifier = \"\".concat(id, \" \").concat(count);\n idCountMap[id] = count + 1;\n var indexByIdentifier = getIndexByIdentifier(identifier);\n var obj = {\n css: item[1],\n media: item[2],\n sourceMap: item[3],\n supports: item[4],\n layer: item[5]\n };\n if (indexByIdentifier !== -1) {\n stylesInDOM[indexByIdentifier].references++;\n stylesInDOM[indexByIdentifier].updater(obj);\n } else {\n var updater = addElementStyle(obj, options);\n options.byIndex = i;\n stylesInDOM.splice(i, 0, {\n identifier: identifier,\n updater: updater,\n references: 1\n });\n }\n identifiers.push(identifier);\n }\n return identifiers;\n}\nfunction addElementStyle(obj, options) {\n var api = options.domAPI(options);\n api.update(obj);\n var updater = function updater(newObj) {\n if (newObj) {\n if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) {\n return;\n }\n api.update(obj = newObj);\n } else {\n api.remove();\n }\n };\n return updater;\n}\nmodule.exports = function (list, options) {\n options = options || {};\n list = list || [];\n var lastIdentifiers = modulesToDom(list, options);\n return function update(newList) {\n newList = newList || [];\n for (var i = 0; i < lastIdentifiers.length; i++) {\n var identifier = lastIdentifiers[i];\n var index = getIndexByIdentifier(identifier);\n stylesInDOM[index].references--;\n }\n var newLastIdentifiers = modulesToDom(newList, options);\n for (var _i = 0; _i < lastIdentifiers.length; _i++) {\n var _identifier = lastIdentifiers[_i];\n var _index = getIndexByIdentifier(_identifier);\n if (stylesInDOM[_index].references === 0) {\n stylesInDOM[_index].updater();\n stylesInDOM.splice(_index, 1);\n }\n }\n lastIdentifiers = newLastIdentifiers;\n };\n};","\"use strict\";\n\nvar memo = {};\n\n/* istanbul ignore next */\nfunction getTarget(target) {\n if (typeof memo[target] === \"undefined\") {\n var styleTarget = document.querySelector(target);\n\n // Special case to return head of iframe instead of iframe itself\n if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {\n try {\n // This will throw an exception if access to iframe is blocked\n // due to cross-origin restrictions\n styleTarget = styleTarget.contentDocument.head;\n } catch (e) {\n // istanbul ignore next\n styleTarget = null;\n }\n }\n memo[target] = styleTarget;\n }\n return memo[target];\n}\n\n/* istanbul ignore next */\nfunction insertBySelector(insert, style) {\n var target = getTarget(insert);\n if (!target) {\n throw new Error(\"Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.\");\n }\n target.appendChild(style);\n}\nmodule.exports = insertBySelector;","\"use strict\";\n\n/* istanbul ignore next */\nfunction insertStyleElement(options) {\n var element = document.createElement(\"style\");\n options.setAttributes(element, options.attributes);\n options.insert(element, options.options);\n return element;\n}\nmodule.exports = insertStyleElement;","\"use strict\";\n\n/* istanbul ignore next */\nfunction setAttributesWithoutAttributes(styleElement) {\n var nonce = typeof __webpack_nonce__ !== \"undefined\" ? __webpack_nonce__ : null;\n if (nonce) {\n styleElement.setAttribute(\"nonce\", nonce);\n }\n}\nmodule.exports = setAttributesWithoutAttributes;","\"use strict\";\n\n/* istanbul ignore next */\nfunction apply(styleElement, options, obj) {\n var css = \"\";\n if (obj.supports) {\n css += \"@supports (\".concat(obj.supports, \") {\");\n }\n if (obj.media) {\n css += \"@media \".concat(obj.media, \" {\");\n }\n var needLayer = typeof obj.layer !== \"undefined\";\n if (needLayer) {\n css += \"@layer\".concat(obj.layer.length > 0 ? \" \".concat(obj.layer) : \"\", \" {\");\n }\n css += obj.css;\n if (needLayer) {\n css += \"}\";\n }\n if (obj.media) {\n css += \"}\";\n }\n if (obj.supports) {\n css += \"}\";\n }\n var sourceMap = obj.sourceMap;\n if (sourceMap && typeof btoa !== \"undefined\") {\n css += \"\\n/*# sourceMappingURL=data:application/json;base64,\".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), \" */\");\n }\n\n // For old IE\n /* istanbul ignore if */\n options.styleTagTransform(css, styleElement, options.options);\n}\nfunction removeStyleElement(styleElement) {\n // istanbul ignore if\n if (styleElement.parentNode === null) {\n return false;\n }\n styleElement.parentNode.removeChild(styleElement);\n}\n\n/* istanbul ignore next */\nfunction domAPI(options) {\n if (typeof document === \"undefined\") {\n return {\n update: function update() {},\n remove: function remove() {}\n };\n }\n var styleElement = options.insertStyleElement(options);\n return {\n update: function update(obj) {\n apply(styleElement, options, obj);\n },\n remove: function remove() {\n removeStyleElement(styleElement);\n }\n };\n}\nmodule.exports = domAPI;","\"use strict\";\n\n/* istanbul ignore next */\nfunction styleTagTransform(css, styleElement) {\n if (styleElement.styleSheet) {\n styleElement.styleSheet.cssText = css;\n } else {\n while (styleElement.firstChild) {\n styleElement.removeChild(styleElement.firstChild);\n }\n styleElement.appendChild(document.createTextNode(css));\n }\n}\nmodule.exports = styleTagTransform;","module.exports = __WEBPACK_EXTERNAL_MODULE__53__;","module.exports = __WEBPACK_EXTERNAL_MODULE__941__;","module.exports = __WEBPACK_EXTERNAL_MODULE__104__;","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\tid: moduleId,\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n// expose the modules object (__webpack_modules__)\n__webpack_require__.m = __webpack_modules__;\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","__webpack_require__.b = (typeof document !== 'undefined' && document.baseURI) || self.location.href;\n\n// object to store loaded and loading chunks\n// undefined = chunk not loaded, null = chunk preloaded/prefetched\n// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded\nvar installedChunks = {\n\t792: 0\n};\n\n// no chunk on demand loading\n\n// no prefetching\n\n// no preloaded\n\n// no HMR\n\n// no HMR manifest\n\n// no on chunks loaded\n\n// no jsonp function","__webpack_require__.nc = undefined;","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./webidControl.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./webidControl.css\";\n export default content && content.locals ? content.locals : undefined;\n","/* eslint-disable no-console */\n\nexport function log (...args) {\n console.log(...args)\n}\n\nexport function warn (...args) {\n console.warn(...args)\n}\n\nexport function error (...args) {\n console.error(...args)\n}\n\nexport function trace (...args) {\n console.trace(...args)\n}\n","// Render a control to record the webids we have for this agent\n\nimport * as UI from 'solid-ui'\nimport { store } from 'solid-logic'\nimport { updateMany } from './contactLogic'\nimport * as $rdf from 'rdflib'\nimport './styles/webidControl.css'\nimport * as debug from './debug'\n\nconst ns = UI.ns\nconst widgets = UI.widgets\nconst utils = UI.utils\nconst kb = store\n\nconst wikidataClasses = widgets.publicData.wikidataClasses // @@ move to solid-logic\nconst wikidataParameters = widgets.publicData.wikidataParameters // @@ move to solid-logic\n\nconst WEBID_NOUN = 'WebID'\nconst PUBLICID_NOUN = 'WikiData link'\nconst DOWN_ARROW = UI.icons.iconBase + 'noun_1369241.svg'\nconst UP_ARROW = UI.icons.iconBase + 'noun_1369237.svg'\n\n/// ///////////////////////// Logic\n\nexport async function addWebIDToContacts (person, webid, urlType, kb) {\n /*\n if (!webid.startsWith('https:')) { /// @@ well we will have other protcols like DID\n if (webid.startsWith('http://') {\n webid = 'https:' + webid.slice(5) // @@ No, data won't match in store. Add the 's' on fetch()\n } else {\n throw new Error('Does not look like a webid, must start with https: ' + webid)\n }\n }\n */\n\n // check this is a url\n try {\n // eslint-disable-next-line no-unused-vars\n const _url = new URL(webid)\n } catch (error) {\n throw new Error(`${WEBID_NOUN}: ${webid} is not a valid url.`)\n }\n\n // create a person's webID\n debug.log(`Adding to ${person} a ${WEBID_NOUN}: ${webid}.`)\n const vcardURLThing = kb.bnode()\n const insertables = [\n $rdf.st(person, ns.vcard('url'), vcardURLThing, person.doc()),\n $rdf.st(vcardURLThing, ns.rdf('type'), urlType, person.doc()),\n $rdf.st(vcardURLThing, ns.vcard('value'), webid, person.doc())\n ]\n // insert WebID in groups\n // replace person with WebID in vcard:hasMember (WebID may already exist)\n // insert owl:sameAs\n const groups = kb.each(null, ns.vcard('hasMember'), person)\n let deletables = []\n groups.forEach(group => {\n deletables = deletables.concat(kb.statementsMatching(group, ns.vcard('hasMember'), person, group.doc()))\n insertables.push($rdf.st(group, ns.vcard('hasMember'), kb.sym(webid), group.doc())) // May exist; do we need to check?\n insertables.push($rdf.st(kb.sym(webid), ns.owl('sameAs'), person, group.doc()))\n })\n try {\n await updateMany(deletables, insertables)\n } catch (err) { throw new Error(`Could not create webId ${WEBID_NOUN}: ${webid}.`) }\n}\n\nexport async function removeWebIDFromContacts (person, webid, urlType, kb) {\n debug.log(`Removing from ${person} their ${WEBID_NOUN}: ${webid}.`)\n\n // remove webID from card\n const existing = kb.each(person, ns.vcard('url'), null, person.doc())\n .filter(urlObject => kb.holds(urlObject, ns.rdf('type'), urlType, person.doc()))\n .filter(urlObject => kb.holds(urlObject, ns.vcard('value'), webid, person.doc()))\n if (!existing.length) {\n throw new Error(`Person ${person} does not have ${WEBID_NOUN} ${webid}.`)\n }\n const vcardURLThing = existing[0]\n const deletables = [\n $rdf.st(person, ns.vcard('url'), vcardURLThing, person.doc()),\n $rdf.st(vcardURLThing, ns.rdf('type'), urlType, person.doc()),\n $rdf.st(vcardURLThing, ns.vcard('value'), webid, person.doc())\n ]\n await kb.updater.update(deletables, [])\n\n // remove webIDs from groups\n const groups = kb.each(null, ns.vcard('hasMember'), kb.sym(webid))\n let removeFromGroups = []\n const insertInGroups = []\n groups.forEach(async group => {\n removeFromGroups = removeFromGroups.concat(kb.statementsMatching(kb.sym(webid), ns.owl('sameAs'), person, group.doc()))\n insertInGroups.push($rdf.st(group, ns.vcard('hasMember'), person, group.doc()))\n if (kb.statementsMatching(kb.sym(webid), ns.owl('sameAs'), null, group.doc()).length < 2) {\n removeFromGroups = removeFromGroups.concat(kb.statementsMatching(group, ns.vcard('hasMember'), kb.sym(webid), group.doc()))\n }\n })\n await updateMany(removeFromGroups, insertInGroups)\n}\n\n// Trace things the same as this - other IDs for same thing\n// returns as array of node\nfunction getSameAs (kb, thing, doc) { // Should this recurse?\n const found = new Set()\n const agenda = new Set([thing.uri])\n\n while (agenda.size) {\n const uri = Array.from(agenda)[0] // clumsy\n agenda.delete(uri)\n if (found.has(uri)) continue\n found.add(uri)\n const node = kb.sym(uri)\n kb.each(node, ns.owl('sameAs'), null, doc)\n .concat(kb.each(null, ns.owl('sameAs'), node, doc))\n .forEach(next => {\n debug.log(' OWL sameAs found ' + next)\n agenda.add(next.uri)\n })\n kb.each(node, ns.schema('sameAs'), null, doc)\n .concat(kb.each(null, ns.schema('sameAs'), node, doc))\n .forEach(next => {\n debug.log(' Schema sameAs found ' + next)\n agenda.add(next.uri)\n })\n }\n found.delete(thing.uri) // don't want the one we knew about\n return Array.from(found).map(uri => kb.sym(uri)) // return as array of nodes\n}\n\n// find person webIDs\nexport function getPersonas (kb, person) {\n const lits = vcardWebIDs(kb, person).concat(getSameAs(kb, person, person.doc()))\n const strings = new Set(lits.map(lit => lit.value)) // remove dups\n const personas = [...strings].map(uri => kb.sym(uri)) // The UI tables do better with Named Nodes than Literals\n personas.sort() // for repeatability\n personas.filter(x => !x.sameTerm(person))\n return personas\n}\n\nexport function vcardWebIDs (kb, person, urlType) {\n return kb.each(person, ns.vcard('url'), null, person.doc())\n .filter(urlObject => kb.holds(urlObject, ns.rdf('type'), urlType, person.doc()))\n .map(urlObject => kb.any(urlObject, ns.vcard('value'), null, person.doc()))\n .filter(x => !!x) // remove nulls\n}\n\nexport function isOrganization (agent) {\n const doc = agent.doc()\n return kb.holds(agent, ns.rdf('type'), ns.vcard('Organization'), doc) ||\n kb.holds(agent, ns.rdf('type'), ns.schema('Organization'), doc)\n}\n/// ////////////////////////////////////////////////////////////// UI\n\n// Utility function to render another different pane\n\nexport function renderNamedPane (dom, subject, paneName, dataBrowserContext) {\n const p = dataBrowserContext.session.paneRegistry.byName(paneName)\n const d = p.render(subject, dataBrowserContext) // @@@ change some bits of context!\n d.classList.add('namedPane')\n return d\n}\n\nexport async function renderWebIdControl (person, dataBrowserContext) {\n const options = {\n longPrompt: `Link to a ${WEBID_NOUN}?`,\n idNoun: WEBID_NOUN,\n urlType: ns.vcard('WebID')\n }\n return renderIdControl(person, dataBrowserContext, options)\n}\n\nexport async function renderPublicIdControl (person, dataBrowserContext) {\n let orgClass = kb.sym('http://www.wikidata.org/wiki/Q43229')\n for (const classId in wikidataClasses) {\n if (kb.holds(person, ns.rdf('type'), ns.schema(classId), person.doc())) {\n orgClass = kb.sym(wikidataClasses[classId])\n debug.log(` renderPublicIdControl bingo: ${classId} -> ${orgClass}`)\n }\n }\n const options = {\n longPrompt: `Add a ${PUBLICID_NOUN}?`,\n idNoun: PUBLICID_NOUN,\n urlType: ns.vcard('PublicId'),\n dbLookup: true,\n class: orgClass, // Organization\n queryParams: wikidataParameters\n }\n return renderIdControl(person, dataBrowserContext, options)\n}\n\n// The main control rendered by this module\nexport async function renderIdControl (person, dataBrowserContext, options) {\n // IDs which are as WebId in VCARD data\n // like :me vcard:hasURL [ a vcard:WebId; vcard:value <https://...foo> ]\n //\n // Display the data about x specifically stored at x.doc()\n // in a fold-away thing\n //\n function renderPersona (dom, persona, kb) {\n function profileOpenHandler (_event) {\n profileIsVisible = !profileIsVisible\n main.classList.toggle('collapsed', !profileIsVisible)\n openButton.children[0].src = profileIsVisible ? UP_ARROW : DOWN_ARROW // @@ fragile\n openButton.setAttribute('aria-expanded', profileIsVisible ? 'true' : 'false')\n openButton.setAttribute('aria-label', profileIsVisible ? 'Collapse profile' : 'Expand profile')\n }\n function renderNewRow (webidObject) {\n const webid = new $rdf.Literal(webidObject.uri)\n async function deleteFunction () {\n try {\n await removeWebIDFromContacts(person, webid, options.urlType, kb)\n } catch (err) {\n debug.error(`Error removing Id ${webid} from ${person}: ${err}`)\n div.appendChild(widgets.errorMessageBlock(dom, 'Error removing WebId from profile. If it persists, contact admin.'))\n }\n await refreshWebIDTable()\n }\n const isWebId = options.urlType.sameTerm(ns.vcard('WebID'))\n const delFunParam = options.editable ? deleteFunction : null\n const opts = { deleteFunction: delFunParam, draggable: true }\n if (isWebId) {\n opts.title = webidObject.uri.split('/')[2]\n opts.image = widgets.faviconOrDefault(dom, webidObject.site()) // just for domain\n }\n const row = widgets.personTR(dom, UI.ns.foaf('knows'), webidObject, opts)\n if (isWebId) {\n row.children[1].textConent = opts.title // @@ will be overwritten\n row.classList.add('personaRow--webid')\n }\n row.classList.add('personaRow')\n return row\n }\n\n const div = dom.createElement('div')\n div.classList.add('fullWidth')\n const personaTable = div.appendChild(dom.createElement('table'))\n personaTable.classList.add('fullWidth')\n const nav = personaTable.appendChild(renderNewRow(persona))\n nav.classList.add('fullWidth')\n const mainRow = personaTable.appendChild(dom.createElement('tr'))\n const mainCell = mainRow.appendChild(dom.createElement('td'))\n mainCell.setAttribute('colspan', 3)\n let main\n\n let profileIsVisible = true\n\n const rhs = nav.children[2]\n const openButton = rhs.appendChild(widgets.button(dom, DOWN_ARROW, 'View', profileOpenHandler))\n openButton.classList.add('personaOpenButton')\n openButton.setAttribute('aria-expanded', 'true')\n openButton.setAttribute('aria-label', 'Collapse profile')\n const paneName = isOrganization(person) || isOrganization(persona) ? 'profile' : 'profile' // was default for org\n\n widgets.publicData.loadPublicDataThing(kb, person, persona).then(_resp => {\n // loadPublicDataThing(kb, person, persona).then(_resp => {\n try {\n main = renderNamedPane(dom, persona, paneName, dataBrowserContext)\n main.classList.add('fullWidth')\n // main.style.visibility = 'collapse'\n mainCell.appendChild(main)\n } catch (err) {\n debug.error('Error displaying persona ' + persona + '. Stack: ' + err)\n main = widgets.errorMessageBlock(dom, 'Error displaying profile. If it persists, contact admin.')\n mainCell.appendChild(main)\n }\n }, err => {\n debug.error('Error loading persona ' + persona + '. Stack: ' + err)\n main = widgets.errorMessageBlock(dom, 'Error loading profile. If it persists, contact admin.')\n mainCell.appendChild(main)\n })\n return div\n } // renderPersona\n\n async function refreshWebIDTable () {\n const personas = getPersonas(kb, person)\n utils.syncTableToArrayReOrdered(profileArea, personas, persona => renderPersona(dom, persona, kb))\n }\n async function addOneIdAndRefresh (person, webid) {\n try {\n await addWebIDToContacts(person, webid, options.urlType, kb)\n } catch (err) {\n debug.error('Error adding webId ' + webid + ' to ' + person + '. Stack: ' + err)\n div.appendChild(widgets.errorMessageBlock(dom, 'This is not a valid WebID.'))\n }\n await refreshWebIDTable()\n }\n\n const { dom } = dataBrowserContext\n options = options || {}\n options.editable = kb.updater.editable(person.doc().uri, kb)\n const div = dom.createElement('div')\n div.classList.add('webidControl', 'webidControl--mobile')\n\n if (getPersonas(kb, person).length === 0 && !options.editable) {\n div.classList.add('hidden')\n return div // No point listing an empty list you can't change\n }\n\n const h3 = div.appendChild(dom.createElement('h3'))\n h3.textContent = 'Link to a ' + options.idNoun\n h3.classList.add('contactPanedHeading')\n\n const table = div.appendChild(dom.createElement('table'))\n table.classList.add('fullWidth')\n\n if (options.editable) { // test\n const barOptions = {\n editable: options.editable,\n manualURIEntry: true, // introduced in solid-ui 2.4.2\n idNoun: options.idNoun,\n dbLookup: options.dbLookup\n }\n const acOptions = {\n queryParams: options.queryParams || wikidataParameters,\n targetClass: options.class\n }\n try {\n div.appendChild(await widgets.renderAutocompleteControl(dom, person, barOptions, acOptions, addOneIdAndRefresh))\n } catch (err) {\n debug.error('Render Autocomplete Control failed. Stack:', err)\n div.appendChild(widgets.errorMessageBlock(dom, 'Error rendering autocomplete. If it persists, contact admin.'))\n }\n }\n const profileArea = div.appendChild(dom.createElement('div'))\n await refreshWebIDTable()\n\n return div\n}\n","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./localUtils.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./localUtils.css\";\n export default content && content.locals ? content.locals : undefined;\n","import * as debug from './debug'\nimport * as UI from 'solid-ui'\nimport { store } from 'solid-logic'\nimport './styles/localUtils.css'\n\nconst kb = store\nconst ns = UI.ns\nlet dom\n\nexport function setDom (d) {\n dom = d\n}\n\n// ---------- Accessible modal dialog helpers ----------\n// This code was generated by Generative AI (Raptor mini in GitHub Copilot) based on the following prompt:\n// Regarding accessibility, how should I replace alert()/confirm() with accessible modal dialogs?\n// Let us implement the modals in the localUtils.\n\n// alert()/confirm(). The implementation ensures focus trapping, keyboard\n// support, and hides the rest of the page from screen readers while the\n// dialog is visible.\n\nlet modalOverlay = null\nlet previousFocus = null\n\nfunction ensureModalOverlay () {\n // if we previously created an overlay but it was removed from the document\n // (tests clear body), rebuild it. Checking presence ensures our reference\n // doesn't point at a detached element.\n if (modalOverlay && document.body.contains(modalOverlay)) return modalOverlay\n // otherwise drop stale reference and create a new element\n modalOverlay = null\n // overlay container\n modalOverlay = dom.createElement('div')\n modalOverlay.id = 'contacts-modal'\n modalOverlay.className = 'focus-trap hidden'\n modalOverlay.setAttribute('role', 'presentation')\n\n modalOverlay.innerHTML = `\n <div class=\"modal\" role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"modal-title\" aria-describedby=\"modal-desc\">\n <h2 id=\"modal-title\"></h2>\n <div id=\"modal-desc\"></div>\n <div id=\"modal-buttons\"></div>\n </div>\n `\n\n document.body.appendChild(modalOverlay)\n\n // keyboard handling (esc/tab)\n modalOverlay.addEventListener('keydown', e => {\n if (e.key === 'Escape') {\n e.stopPropagation()\n // simulate cancel if available\n const cancelBtn = modalOverlay.querySelector('button[data-cancel]')\n if (cancelBtn) cancelBtn.click()\n else closeModal(false)\n } else if (e.key === 'Tab') {\n // simple focus trap: cycle through focusable elements inside overlay\n const focusable = Array.from(modalOverlay.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])')).filter(el => !el.hasAttribute('disabled'))\n if (focusable.length === 0) return\n const idx = focusable.indexOf(document.activeElement)\n if (e.shiftKey) {\n if (idx === 0) {\n focusable[focusable.length - 1].focus()\n e.preventDefault()\n }\n } else {\n if (idx === focusable.length - 1) {\n focusable[0].focus()\n e.preventDefault()\n }\n }\n }\n })\n\n return modalOverlay\n}\n\nfunction hideSiblings (hide) {\n const siblings = Array.from(document.body.children).filter(c => c !== modalOverlay)\n siblings.forEach(el => {\n if (hide) el.setAttribute('aria-hidden', 'true')\n else el.removeAttribute('aria-hidden')\n })\n}\n\nfunction openModal ({ title, message, buttons }) {\n const overlay = ensureModalOverlay()\n previousFocus = document.activeElement\n hideSiblings(true)\n overlay.classList.remove('hidden')\n\n overlay.querySelector('#modal-title').textContent = title || ''\n const descEl = overlay.querySelector('#modal-desc')\n if (typeof message === 'string') {\n descEl.textContent = message\n } else {\n // allow passing nodes\n descEl.innerHTML = ''\n descEl.appendChild(message)\n }\n\n const btnContainer = overlay.querySelector('#modal-buttons')\n btnContainer.innerHTML = ''\n\n return new Promise(resolve => {\n buttons.forEach(btn => {\n const b = dom.createElement('button')\n b.setAttribute('type', 'button')\n b.textContent = btn.label\n if (btn.primary) b.classList.add('btn-primary')\n if (btn.cancel) b.setAttribute('data-cancel', 'true')\n b.addEventListener('click', () => {\n closeModal(btn.value)\n resolve(btn.value)\n })\n btnContainer.appendChild(b)\n })\n // focus first button\n const first = btnContainer.querySelector('button')\n if (first) first.focus()\n })\n}\n\nfunction closeModal (result) {\n if (modalOverlay) {\n modalOverlay.classList.add('hidden')\n hideSiblings(false)\n if (previousFocus && previousFocus.focus) previousFocus.focus()\n }\n}\n\n/**\n * Show an alert-style modal that has a single OK button.\n * @param {string} message\n * @param {string} [title]\n * @returns {Promise<true>}\n */\nexport function alertDialog (message, title = 'Information') {\n return openModal({\n title,\n message,\n buttons: [{ label: 'OK', value: true, primary: true }]\n })\n}\n\n/**\n * Show a confirm-style modal returning a boolean.\n * @param {string} message\n * @param {string} [title]\n * @returns {Promise<boolean>}\n */\nexport function confirmDialog (message, title = 'Confirm') {\n return openModal({\n title,\n message,\n buttons: [\n { label: 'Cancel', value: false, cancel: true },\n { label: 'OK', value: true, primary: true }\n ]\n })\n}\n\n// ---------- end of modal helpers ----------\n\n/**\n * Normalize group URIs to ensure consistent representation.\n * Groups should be referenced with fragment #this, e.g., ...Group/AnotherGroup.ttl#this\n * If a group URI ends with .ttl (without #this), add #this\n * @param {string} uri - The group URI to normalize\n * @returns {string} The normalized group URI\n */\nexport function normalizeGroupUri (uri) {\n if (uri && uri.endsWith('.ttl')) {\n return uri + '#this'\n }\n return uri\n}\n\nexport function complain (div, d, message) {\n div.appendChild(UI.widgets.errorMessageBlock(d, message, 'pink'))\n}\n\nexport function getSameAs (kb, item, doc) {\n return kb.each(item, ns.owl('sameAs'), null, doc).concat(\n kb.each(null, ns.owl('sameAs'), item, doc))\n}\n// For deleting an addressbook sub-folder eg person - use with care!\n// @@ move to solid-logic\nexport function deleteRecursive (kb, folder) {\n return new Promise(function (resolve, reject) {\n kb.fetcher.load(folder).then(function () {\n const promises = kb.each(folder, ns.ldp('contains')).map(file => {\n if (kb.holds(file, ns.rdf('type'), ns.ldp('BasicContainer'))) {\n return deleteRecursive(kb, file)\n } else {\n debug.log('Recursive delete - we delete file ' + file.uri)\n return kb.fetcher.webOperation('DELETE', file.uri)\n }\n })\n debug.log('Recursive delete - we delete folder ' + folder.uri)\n promises.push(kb.fetcher.webOperation('DELETE', folder.uri))\n Promise.all(promises).then(_res => {\n resolve()\n }).catch(reject)\n }).catch(reject)\n })\n}\n\n// In a LDP work, deletes the whole document describing a thing\n// plus patch out ALL mentiosn of it! Use with care!\n// beware of other data picked up from other places being smushed\n// together and then deleted.\nexport async function deleteThingAndDoc (x) {\n const name = nameFor(x)\n if (!(await confirmDialog('Really DELETE ' + name + '?'))) {\n throw new Error('User cancelled contact deletion')\n }\n debug.log('deleteThingAndDoc - to be deleted ' + x)\n const ds = kb.statementsMatching(x).concat(kb.statementsMatching(undefined, undefined, x))\n try {\n await kb.updater.updateMany(ds)\n await kb.fetcher.delete(x.doc())\n debug.log('deleteThingAndDoc - deleted')\n } catch (err) {\n debug.error('Error deleting ' + x + '. Stack: ' + err)\n throw new Error('An error occured while deleting.')\n }\n}\n\nexport function compareForSort (self, other) {\n let s = nameFor(self)\n let o = nameFor(other)\n if (s && o) {\n s = s.toLowerCase()\n o = o.toLowerCase()\n if (s > o) return 1\n if (s < o) return -1\n }\n if (self.uri > other.uri) return 1\n if (self.uri < other.uri) return -1\n return 0\n}\n\n// organization-name is a hack for Mac records with no FN which is mandatory.\nexport function nameFor (x) {\n const name =\n kb.any(x, ns.vcard('fn')) ||\n kb.any(x, ns.foaf('name')) ||\n kb.any(x, ns.vcard('organization-name'))\n return name ? name.value : '???'\n}\n\n/**\n * Prevent keyboard tabbing into labels/label-like links created by rdflib/solid-ui forms.\n * @param {HTMLElement} root\n */\nexport function skipLabelsFromTabbing (root) {\n // Many Solid-UI forms render field labels as focusable links (hrefs).\n // Make sure keyboard tabbing skips these label links entirely.\n const selectors = [\n 'label',\n '.formFieldName a',\n '.classifierBox-label a',\n '.choiceBox-label a',\n '.label a',\n // Skip focusable label-like links created by Solid-UI forms, including the vcard note link\n 'a[href=\"http://www.w3.org/2006/vcard/ns#note\"]',\n 'a[href$=\"#note\"]',\n ].join(', ')\n\n // Some environments have NodeLists without forEach (e.g., older Safari).\n const nodes = root?.querySelectorAll?.(selectors)\n if (!nodes) return\n\n Array.from(nodes).forEach(el => {\n // Some browsers may return null for tabIndex, and some elements may not\n // expose tabIndex at all (e.g., SVG elements), so guard before setting.\n if (typeof el.tabIndex === 'number' && el.tabIndex !== -1) {\n el.tabIndex = -1\n }\n // Ensure those label links are not announced as focusable elements\n if (el.getAttribute('aria-hidden') !== 'true') {\n el.setAttribute('aria-hidden', 'true')\n }\n })\n}\n\nexport function isAWebID (subject) {\n const t = kb.findTypeURIs(subject.doc())\n return !!t[ns.foaf('PersonalProfileDocument').uri]\n}\n\n// Make the layout stack vertically when the containing pane gets narrow\nexport function setupResponsiveStacking (paneDiv, breakpoint = 900) {\n function updateResponsiveState () {\n const width = paneDiv.getBoundingClientRect().width\n const paneNarrow = width > 0 ? width <= breakpoint : false\n const viewportNarrow = (typeof window !== 'undefined' && typeof window.matchMedia === 'function')\n ? window.matchMedia('(max-width: ' + breakpoint + 'px)').matches\n : false\n const isNarrow = width > 0 ? paneNarrow : viewportNarrow\n\n if (width > 0) {\n paneDiv.dataset.paneWidth = Math.round(width).toString()\n paneDiv.dataset.paneNarrow = paneNarrow ? 'true' : 'false'\n } else {\n // If not inserted yet, apply viewport mode until placed.\n paneDiv.dataset.paneWidth = '0'\n paneDiv.dataset.paneNarrow = viewportNarrow ? 'true' : 'false'\n }\n\n paneDiv.classList.toggle('contactPane--narrow', isNarrow)\n paneDiv.dataset.viewportNarrow = viewportNarrow ? 'true' : 'false'\n\n return isNarrow\n }\n\n // Debounce utility\n function debounce (fn, delay) {\n let timer = null\n return function (...args) {\n clearTimeout(timer)\n timer = setTimeout(() => fn.apply(this, args), delay)\n }\n }\n\n const debouncedUpdate = debounce(() => {\n updateResponsiveState()\n }, 100)\n\n const resizeObserverAvailable = typeof ResizeObserver !== 'undefined'\n if (resizeObserverAvailable) {\n const ro = new ResizeObserver(() => {\n debouncedUpdate()\n })\n ro.observe(paneDiv)\n }\n\n if (typeof window !== 'undefined' && typeof window.addEventListener === 'function') {\n window.addEventListener('resize', debouncedUpdate)\n }\n\n // Initial state\n function ensureInitialUpdate () {\n // Call both updaters for their side effects (setting dataset attributes).\n // Return values are intentionally discarded — ESLint-safe.\n updateResponsiveState()\n // If we are not in the document yet, re-run until connected\n if (!paneDiv.isConnected) {\n requestAnimationFrame(ensureInitialUpdate)\n }\n }\n\n ensureInitialUpdate()\n}\n","import * as UI from 'solid-ui'\nimport * as $rdf from 'rdflib'\nimport { store } from 'solid-logic'\nimport { getPersonas } from './webidControl'\nimport * as debug from './debug'\nimport { getSameAs, confirmDialog, alertDialog } from './localUtils'\n\nconst ns = UI.ns\nconst utils = UI.utils\nconst kb = store\nconst updater = kb.updater\n\n/** Perform updates on more than one document @@ Move to rdflib!\n*/\nexport async function updateMany (deletions, insertions = []) {\n const docs = deletions.concat(insertions).map(st => st.why)\n const uniqueDocs = []\n docs.forEach(doc => {\n if (!uniqueDocs.find(uniqueDoc => uniqueDoc.equals(doc))) uniqueDocs.push(doc)\n })\n const updates = uniqueDocs.map(doc =>\n kb.updater.update(deletions.filter(st => st.why.sameTerm(doc)),\n insertions.filter(st => st.why.sameTerm(doc))))\n return Promise.all(updates)\n}\n\n/** Add a new person to the web data\n*\n* adds them to the given groups as well.\n* @returns {NamedNode} the person\n*/\nexport async function saveNewContact (book, name, selectedGroups, klass) {\n await kb.fetcher.load(book.doc())\n const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))\n\n const uuid = utils.genUuid()\n const person = kb.sym(\n book.dir().uri + 'Person/' + uuid + '/index.ttl#this'\n )\n const doc = person.doc()\n\n // Set of statements to different files\n const agenda = [\n // Patch the main index to add the person\n $rdf.st(person, ns.vcard('inAddressBook'), book, nameEmailIndex), // The people index\n $rdf.st(person, ns.vcard('fn'), name, nameEmailIndex),\n // The new person file\n $rdf.st(person, ns.vcard('fn'), name, doc),\n $rdf.st(person, ns.rdf('type'), klass, doc),\n\n $rdf.st(doc, ns.dct('created'), new Date(), doc) // Note when created - useful for triaging later\n // Note this is propert of the file -- not when the person was created!\n ]\n\n // `selectedGroups` may be an array (older callers) or an object map\n // (contactsPane.js tracks it as `{ uri: true }`). Normalize and make sure\n // at least one group is selected before proceeding – otherwise we return\n // `undefined` and the caller must handle it.\n const groups = Array.isArray(selectedGroups)\n ? selectedGroups\n : Object.keys(selectedGroups || {})\n\n if (groups.length > 0) {\n for (const gu of groups) {\n const g = kb.sym(gu)\n const gd = g.doc()\n agenda.push(\n $rdf.st(g, ns.vcard('hasMember'), person, gd),\n $rdf.st(person, ns.vcard('fn'), name, gd)\n )\n }\n } else {\n alertDialog('Must be a member of at least one group. Please select or create a group.')\n return // caller should check for undefined result\n }\n\n try {\n await updater.updateMany([], agenda)\n } catch (e) {\n debug.error('Cannot add group membership for ' + person + '. Stack:' + e)\n throw new Error('Save new contact')\n }\n return person\n}\n\nexport function sanitizeToAlpha (name) { // https://mathiasbynens.be/notes/es6-unicode-regex\n const n2 = name.replace(/\\W/gu, '_') // Anything which is not a unicode word characeter\n return n2.replace(/_+/g, '_') // https://www.regular-expressions.info/shorthand.html\n}\n\n/** Write new group to web\n * Creates an empty new group file and adds it to the index\n * @returns group\n*/\nexport async function saveNewGroup (book, name) {\n await kb.fetcher.load(book.doc())\n const gix = kb.any(book, ns.vcard('groupIndex'))\n\n const gname = sanitizeToAlpha(name)\n const group = kb.sym(book.dir().uri + 'Group/' + gname + '.ttl#this')\n const doc = group.doc()\n // debug.log(' New group will be: ' + group + '\\n')\n try {\n await kb.fetcher.load(gix)\n } catch (err) {\n throw new Error('Error loading group index!' + gix.uri + ': ' + err)\n }\n if (kb.holds(book, ns.vcard('includesGroup'), group, gix)) {\n return group // Already exists\n }\n const insertTriples = [\n $rdf.st(book, ns.vcard('includesGroup'), group, gix),\n $rdf.st(group, ns.rdf('type'), ns.vcard('Group'), gix),\n $rdf.st(group, ns.vcard('fn'), name, gix)\n ]\n try {\n await updater.update([], insertTriples)\n } catch (e) {\n throw new Error('Could not update group index ' + e) // fail\n }\n\n const triples = [\n $rdf.st(book, ns.vcard('includesGroup'), group, doc), // Pointer back to book\n $rdf.st(group, ns.rdf('type'), ns.vcard('Group'), doc),\n $rdf.st(group, ns.vcard('fn'), name, doc)\n ]\n try {\n await updater.update([], triples)\n } catch (err) {\n throw new Error('Could not update group file: ' + err) // fail\n }\n return group\n}\n\nexport async function addPersonToGroup (thing, group) {\n const toBeFetched = [thing.doc(), group.doc()]\n try {\n await kb.fetcher.load(toBeFetched)\n } catch (e) {\n debug.error('Error adding ' + thing + ' to group ' + group + '. Stack: ' + e)\n throw new Error('Error adding to group.')\n }\n\n const types = kb.findTypeURIs(thing)\n\n if (!(ns.vcard('Individual').uri in types ||\n ns.vcard('Organization').uri in types)) {\n debug.warn('Thing ' + thing + ' is not an Individual or Organization, but has types: ' + Object.keys(types))\n alertDialog('You are trying to add something else than an individual or organization.')\n return\n }\n let pname = kb.any(thing, ns.vcard('fn'))\n const gname = kb.any(group, ns.vcard('fn'))\n if (!pname) {\n debug.warn('Thing ' + thing + ' has no vcard:fn')\n alertDialog('What you are trying to add seems to have no full name.')\n return\n }\n const already = kb.holds(thing, ns.vcard('fn'), null, group.doc())\n if (already) {\n if (pname === '') pname = 'Contact'\n alertDialog(pname + ' already exists in group ' + gname + '.')\n return\n }\n const message = 'Add ' + pname + ' to group ' + gname + '?'\n if (!await confirmDialog(message)) return\n const ins = [\n $rdf.st(thing, ns.vcard('fn'), pname, group.doc())\n ]\n // find person webIDs and insert in vcard:hasMember\n const webIDs = getPersonas(kb, thing).map(webid => webid.value)\n if (webIDs.length) {\n webIDs.forEach(webid => {\n ins.push($rdf.st(kb.sym(webid), ns.owl('sameAs'), thing, group.doc()))\n ins.push($rdf.st(group, ns.vcard('hasMember'), kb.sym(webid), group.doc()))\n })\n } else {\n ins.push($rdf.st(group, ns.vcard('hasMember'), thing, group.doc()))\n }\n try {\n await updater.update([], ins)\n // to allow refresh of card groupList\n kb.fetcher.unload(group.doc())\n await kb.fetcher.load(group.doc())\n } catch (e) {\n debug.error('Error adding ' + thing + ' to group ' + group + '. Stack: ' + e)\n throw new Error('Error adding to group.')\n }\n return thing\n}\n\n/**\n * Find persons member of a group\n */\n\nexport function groupMembers (kb, group) {\n const a = kb.each(group, ns.vcard('hasMember'), null, group.doc())\n let b = []\n a.forEach(item => {\n /* const contacts = kb.each(item, ns.owl('sameAs'), null, group.doc())\n if (contacts.length) {\n if (!kb.any(contacts[0], ns.vard('fn'))) b = b.concat(item) // this is the old data model\n else b = b.concat(contacts)\n } else { b = b.concat(item) }\n b = b.concat(item) */\n\n // to keep compatibility with old data model\n // check if item is a contact, else it is a WebID and parse 'sameAs' for contacts\n b = kb.any(item, ns.vcard('fn'), null, group.doc()) ? b.concat(item) : b.concat(kb.each(item, ns.owl('sameAs'), null, group.doc()))\n })\n const strings = new Set(b.map(contact => contact.uri)) // remove dups\n b = [...strings].map(uri => kb.sym(uri))\n return b\n}\n\nexport function isLocal (group, item) {\n const tree = group.dir().dir().dir()\n const local = item.uri && item.uri.startsWith(tree.uri)\n // debug.log(` isLocal ${local} for ${item.uri} in group ${group} tree ${tree.uri}`)\n return local\n}\n\nexport async function getDataModelIssues (groups) {\n const del = []\n const ins = []\n groups.forEach(group => {\n const members = kb.each(group, ns.vcard('hasMember'), null, group.doc())\n members.forEach((member) => {\n const others = getSameAs(kb, member, group.doc())\n if (others.length && isLocal(group, member)) { // Problem: local ID used instead of webID\n for (const other of others) {\n if (!isLocal(group, other)) { // Let's use this one as the immediate member for CSS ACLs'\n // console.warn(`getDataModelIssues: Need to swap ${member} to ${other}`)\n del.push($rdf.st(group, ns.vcard('hasMember'), member, group.doc()))\n ins.push($rdf.st(group, ns.vcard('hasMember'), other, group.doc()))\n break\n }\n // debug.log('getDataModelIssues: ??? expected id not to be local ' + other)\n } // other\n } // if\n }) // member\n }) // next group\n return { del, ins }\n} // getDataModelIssues\n\n// Ends\n","import * as UI from 'solid-ui'\nimport { solidLogicSingleton } from 'solid-logic'\nimport * as $rdf from 'rdflib'\nimport { complain } from './localUtils'\nimport * as debug from './debug'\n\nconst { setACLUserPublic } = solidLogicSingleton.acl\n// const mime = require('mime-types')\n// const toolsPane0 = require('./toolsPane')\n// const toolsPane = toolsPane0.toolsPane\n\n// const ns = UI.ns\n// const utils = UI.utils\n\n// Mint a new address book\n\nexport function mintNewAddressBook (dataBrowserContext, context) {\n return new Promise(function (resolve, reject) {\n UI.login.ensureLoadedProfile(context).then(\n context => {\n // 20180713\n debug.log('Logged in as ' + context.me)\n const me = context.me\n\n const dom = context.dom\n const div = context.div\n const kb = dataBrowserContext.session.store\n const ns = UI.ns\n const newBase = context.newBase || context.newInstance.dir().uri\n const instanceClass = context.instanceClass || ns.vcard('AddressBook')\n\n if (instanceClass.sameTerm(ns.vcard('Group'))) {\n // Make a group not an address book\n const g =\n context.newInstance || kb.sym(context.newBase + 'index.ttl#this')\n const doc = g.doc()\n kb.add(g, ns.rdf('type'), ns.vcard('Group'), doc)\n kb.add(\n g,\n ns.vcard('fn'),\n context.instanceName || 'untitled group',\n doc\n ) // @@ write doc back\n kb.fetcher\n .putBack(doc, { contentType: 'text/turtle' })\n .then(function (_xhr) {\n resolve(context)\n })\n .catch(function (err) {\n debug.error('Failed to fetch new address book. Stack: ' + err)\n reject(\n new Error('Error creating document for new group ' + err)\n )\n })\n return\n }\n const appInstanceNoun = 'address book'\n\n let bookContents = `@prefix vcard: <http://www.w3.org/2006/vcard/ns#>.\n @prefix ab: <http://www.w3.org/ns/pim/ab#>.\n @prefix dc: <http://purl.org/dc/elements/1.1/>.\n @prefix xsd: <http://www.w3.org/2001/XMLSchema#>.\n\n <#this> a vcard:AddressBook;\n dc:title \"New address Book\";\n vcard:nameEmailIndex <people.ttl>;\n vcard:groupIndex <groups.ttl>.\n`\n\n bookContents +=\n '<#this> <http://www.w3.org/ns/auth/acl#owner> <' +\n me.uri +\n '>.\\n\\n'\n\n const newAppInstance = kb.sym(newBase + 'index.ttl#this')\n\n const toBeWritten = [\n {\n to: 'index.ttl',\n content: bookContents,\n contentType: 'text/turtle'\n },\n { to: 'groups.ttl', content: '', contentType: 'text/turtle' },\n { to: 'people.ttl', content: '', contentType: 'text/turtle' },\n { to: '', existing: true, aclOptions: { defaultForNew: true } }\n ]\n\n // @@ Ask user abut ACLs?\n\n //\n // @@ Add header to PUT If-None-Match: * to prevent overwrite\n //\n\n function claimSuccess (newAppInstance, appInstanceNoun) {\n // @@ delete or grey other stuff\n debug.log(`New ${appInstanceNoun} created at ${newAppInstance}`)\n const p = div.appendChild(dom.createElement('p'))\n p.classList.add('claimSuccess')\n p.innerHTML =\n 'Your <a href=\\'' +\n newAppInstance.uri +\n '\\'><b>new ' +\n appInstanceNoun +\n '</b></a> is ready. ' +\n '<br/><br/><a href=\\'' +\n newAppInstance.uri +\n '\\'>Go to new ' +\n appInstanceNoun +\n '</a>'\n const newContext = Object.assign(\n { newInstance: newAppInstance },\n context\n )\n resolve(newContext)\n }\n\n function doNextTask () {\n function checkOKSetACL (uri, ok) {\n if (!ok) {\n return reject(new Error('Error writing new file ' + task.to))\n }\n\n setACLUserPublic(dest, me, aclOptions)\n .then(() => doNextTask())\n .catch(err => {\n debug.error('Error setting access permissions for ' + task.to + '. Stack: ' + err)\n const message =\n 'Error setting access permissions for ' +\n task.to +\n '.'\n return reject(new Error(message))\n })\n }\n\n if (toBeWritten.length === 0) {\n claimSuccess(newAppInstance, appInstanceNoun)\n } else {\n var task = toBeWritten.shift() /* eslint-disable-line no-var */\n debug.log('Creating new file ' + task.to + ' in new instance ')\n var dest = $rdf.uri.join(task.to, newBase) /* eslint-disable-line no-var */\n var aclOptions = task.aclOptions || {} /* eslint-disable-line no-var */\n\n if ('content' in task) {\n kb.fetcher\n .webOperation('PUT', dest, {\n data: task.content,\n saveMetadata: true,\n contentType: task.contentType\n })\n .then(() => checkOKSetACL(dest, true))\n } else if ('existing' in task) {\n checkOKSetACL(dest, true)\n } else {\n reject(new Error('Copy not expected while buiding new app.'))\n // const from = task.from || task.to // default source to be same as dest\n // UI.widgets.webCopy(base + from, dest, task.contentType, checkOKSetACL)\n }\n }\n }\n doNextTask()\n },\n err => {\n // log in then\n debug.warn('Error logging in. Stack: ' + err)\n complain(context.div, context.dom, 'Please log in to create a new address book.')\n }\n )\n })\n}\n","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./mugshotGallery.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./mugshotGallery.css\";\n export default content && content.locals ? content.locals : undefined;\n","import * as UI from 'solid-ui'\nimport { store } from 'solid-logic'\nimport * as $rdf from 'rdflib'\nimport './styles/mugshotGallery.css'\nimport * as debug from './debug'\nimport { confirmDialog, alertDialog } from './localUtils'\n\n// Lightweight MIME helpers replacing the heavy mime-types/mime-db packages (~170 KiB)\nconst mimeMap = {\n 'image/png': 'png',\n 'image/jpeg': 'jpg',\n 'image/gif': 'gif',\n 'image/svg+xml': 'svg',\n 'image/webp': 'webp',\n 'image/bmp': 'bmp',\n 'image/tiff': 'tiff',\n 'application/pdf': 'pdf',\n 'text/plain': 'txt',\n 'text/html': 'html',\n 'application/json': 'json',\n 'application/octet-stream': 'bin'\n}\nconst extMap = Object.fromEntries(Object.entries(mimeMap).map(([k, v]) => [v, k]))\nconst mime = {\n extension: (contentType) => mimeMap[contentType] || false,\n lookup: (filename) => {\n const ext = filename.split('.').pop().toLowerCase()\n return extMap[ext] || false\n }\n}\n\nconst ns = UI.ns\nconst utils = UI.utils\nconst kb = store\n\n/* Mugshot Gallery\n*\n* A widget for managing a set of images.\n* Make this a form field?\n*/\nexport function renderMugshotGallery (dom, subject) {\n function localComplain (message) {\n galleryDiv.appendChild(UI.widgets.errorMessageBlock(dom, message, 'pink'))\n }\n\n async function linkToPicture (subject, pic, remove) {\n const link = [\n $rdf.st(subject, ns.vcard('hasPhoto'), pic, subject.doc())\n ]\n try {\n if (remove) {\n await kb.updater.update(link, [])\n } else {\n await kb.updater.update([], link)\n }\n } catch (err) {\n const msg = 'Writing back image link FAILED ' + pic + '. Stack: ' + err\n debug.error(msg)\n throw new Error('Writing back image link FAILED')\n }\n }\n\n function handleDroppedThing (thing) {\n kb.fetcher.nowOrWhenFetched(thing.doc(), function (ok, mess) {\n if (!ok) {\n debug.error('Error looking up dropped thing ' + thing + '. Stack: ' + mess)\n } else {\n const types = kb.findTypeURIs(thing)\n for (const ty in types) {\n debug.log('drop object type includes: ' + ty) // @@ Allow email addresses and phone numbers to be dropped?\n }\n debug.log('Default: assume web page ' + thing) // icon was: UI.icons.iconBase + 'noun_25830.svg'\n kb.add(subject, ns.wf('attachment'), thing, subject.doc())\n // @@ refresh UI\n }\n })\n }\n\n function uploadFileToContact (filename, contentType, data) {\n // const fileExtension = filename.split('.').pop() // .toLowerCase()\n const extension = mime.extension(contentType)\n if (contentType !== mime.lookup(filename)) {\n filename += '_.' + extension\n debug.warn('MIME TYPE MISMATCH -- adding extension: ' + filename)\n }\n let prefix, predicate\n const isImage = contentType.startsWith('image')\n if (isImage) {\n prefix = 'image_'\n predicate = ns.vcard('hasPhoto')\n } else {\n prefix = 'attachment_'\n predicate = ns.wf('attachment')\n }\n\n let n, pic\n for (n = 0; ; n++) {\n // Check filename is not used or invent new one\n pic = kb.sym(subject.dir().uri + filename)\n if (!kb.holds(subject, ns.vcard('hasPhoto'), pic)) {\n break\n }\n filename = prefix + n + '.' + extension\n }\n debug.log(\n 'Putting ' +\n data.byteLength +\n ' bytes of ' +\n contentType +\n ' to ' +\n pic\n )\n kb.fetcher\n .webOperation('PUT', pic.uri, {\n data,\n contentType\n })\n .then(function (response) {\n if (!response.ok) {\n debug.error('Upload of ' + pic + ' failed: ' + response.status + ' ' + response.statusText)\n localComplain('Error uploading picture. If the problem persists, contact admin.')\n return\n }\n debug.log('Upload picture put OK: ' + pic)\n kb.add(subject, predicate, pic, subject.doc())\n kb.fetcher\n .putBack(subject.doc(), { contentType: 'text/turtle' })\n .then(\n function (_response) {\n if (isImage) {\n mugshotDiv.refresh()\n }\n },\n function (err) {\n debug.error(' Write back image link FAIL ' + pic + '. Stack: ' + err)\n }\n )\n })\n }\n\n // When a set of URIs are dropped on\n async function handleURIsDroppedOnMugshot (uris) {\n for (const u of uris) {\n let thing = $rdf.sym(u) // Attachment needs text label to disinguish I think not icon.\n debug.log('Dropped on mugshot thing ' + thing) // icon was: UI.icons.iconBase + 'noun_25830.svg'\n if (u.startsWith('http') && u.indexOf('#') < 0) {\n // Plain document\n // Take a copy of a photo on the web:\n if (u.startsWith('http:')) { // because of browser mixed content stuff can't read http:\n thing = $rdf.sym('https:' + u.slice(5))\n }\n const options = { withCredentials: false, credentials: 'omit' }\n let result\n try {\n result = await kb.fetcher.webOperation('GET', thing.uri, options)\n } catch (err) {\n debug.error('Fetch error trying to GET picture ' + thing + '. Stack: ' + err)\n handleDroppedThing(thing)\n return\n }\n const contentType = result.headers.get('Content-Type')\n let pathEnd = thing.uri.split('/').slice(-1)[0] // last segment as putative filename\n pathEnd = pathEnd.split('?')[0] // chop off any query params\n const data = await result.arrayBuffer()\n if (!result.ok) {\n debug.error('Cant download, so will link image. ' + thing + ':' + result.status)\n handleDroppedThing(thing)\n return\n }\n uploadFileToContact(pathEnd, contentType, data)\n return\n } else {\n localComplain('Not a web document URI, cannot copy ' + thing + ' as picture.')\n }\n handleDroppedThing(thing)\n }\n }\n\n // Drop an image file to set up the mugshot\n function droppedFileHandler (files) {\n for (let i = 0; i < files.length; i++) {\n const f = files[i]\n debug.log(\n ' contacts: Filename: ' +\n f.name +\n ', type: ' +\n (f.type || 'n/a') +\n ' size: ' +\n f.size +\n ' bytes, last modified: ' +\n (f.lastModifiedDate\n ? f.lastModifiedDate.toLocaleDateString()\n : 'n/a')\n ) // See e.g. https://www.html5rocks.com/en/tutorials/file/dndfiles/\n\n // @@ Add: progress bar(s)\n const reader = new FileReader()\n reader.onload = (function (theFile) {\n return function (e) {\n const data = e.target.result\n debug.log(' File read byteLength : ' + data.byteLength)\n const filename = encodeURIComponent(theFile.name)\n const contentType = theFile.type\n uploadFileToContact(filename, contentType, data)\n }\n })(f)\n reader.readAsArrayBuffer(f)\n }\n }\n\n function elementForImage (image) {\n const img = dom.createElement('img')\n img.classList.add('mugshotImage')\n img.setAttribute('alt', image ? 'Contact photo' : 'Drop photo here')\n UI.widgets.makeDropTarget(\n img,\n handleURIsDroppedOnMugshot,\n droppedFileHandler\n )\n if (image) {\n // img.setAttribute('src', image.uri) use token and works with NSS but not with CSS\n // we need to get image with authenticated fetch\n store.fetcher._fetch(image.uri)\n .then(function (response) {\n return response.blob()\n })\n .then(function (myBlob) {\n const objectURL = URL.createObjectURL(myBlob)\n img.setAttribute('src', objectURL)\n })\n UI.widgets.makeDraggable(img, image)\n }\n return img\n }\n\n function syncMugshots () {\n let images = kb.each(subject, ns.vcard('hasPhoto')) // Priviledge vcard ones\n images.sort() // arbitrary consistency\n images = images.slice(0, 5) // max number for the space\n if (images.length === 0) {\n mugshotDiv.innerHTML = '' // strictly, don't remove it if already there\n if (editable) {\n mugshotDiv.appendChild(placeholder) // A head image to drop pictures on\n } // otherwise leave gallery empty .. nothing to see here folks\n } else {\n utils.syncTableToArray(mugshotDiv, images, elementForImage)\n }\n }\n\n // Good URI for a Camera picture\n function getImageDoc () {\n const imageDoc = kb.sym(\n subject.dir().uri + 'Image_' + Date.now() + '.png'\n )\n return imageDoc\n }\n // Store picture\n async function tookPicture (imageDoc) {\n if (imageDoc) {\n await linkToPicture(subject, imageDoc)\n syncMugshots()\n }\n }\n\n function trashCan () {\n const button = UI.widgets.button(\n dom,\n UI.icons.iconBase + 'noun_925021.svg',\n 'Drag here to delete',\n undefined,\n { 'aria-label': 'Delete picture - drag picture here' }\n )\n async function droppedURIHandler (uris) {\n const images = kb\n .each(subject, ns.vcard('hasPhoto'))\n .map(x => x.uri)\n for (const uri of uris) {\n if (!images.includes(uri)) {\n alertDialog('Only drop pictures onto this trash can.')\n return\n }\n if (await confirmDialog('Really DELETE picture?')) {\n try {\n debug.log('Unlinking image file ' + uri)\n await linkToPicture(subject, kb.sym(uri), true)\n debug.log('Deleting image file ' + uri)\n await kb.fetcher.webOperation('DELETE', uri)\n } catch (err) {\n const msg = 'Error deleting picture. If it persists, contact your admin.'\n localComplain(msg)\n return\n }\n }\n }\n syncMugshots()\n }\n UI.widgets.makeDropTarget(button, droppedURIHandler, null)\n return button\n }\n\n function renderImageTools () {\n const imageToolTable = dom.createElement('table')\n const row = imageToolTable.appendChild(dom.createElement('tr'))\n const left = row.appendChild(dom.createElement('td'))\n const middle = row.appendChild(dom.createElement('td'))\n const right = row.appendChild(dom.createElement('td'))\n\n left.appendChild(\n UI.media.cameraButton(dom, kb, getImageDoc, tookPicture)\n )\n try {\n middle.appendChild(\n UI.widgets.fileUploadButtonDiv(dom, droppedFileHandler)\n )\n } catch (e) {\n debug.log('ignore fileUploadButtonDiv error for now', e)\n }\n right.appendChild(trashCan())\n return imageToolTable\n }\n\n // Body of renderMugshotGallery\n\n const editable = kb.updater.editable(subject.doc().uri, kb)\n const galleryDiv = dom.createElement('div')\n const mugshotDiv = galleryDiv.appendChild(dom.createElement('div'))\n const placeholder = elementForImage()\n UI.widgets.setImage(placeholder, subject) // Fallback icon or get from web\n syncMugshots()\n mugshotDiv.refresh = syncMugshots\n if (editable) {\n galleryDiv.appendChild(renderImageTools())\n }\n return galleryDiv\n}\n","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./groupMembership.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./groupMembership.css\";\n export default content && content.locals ? content.locals : undefined;\n","import { addPersonToGroup, groupMembers, getDataModelIssues } from './contactLogic'\nimport * as UI from 'solid-ui'\nimport { authn, store } from 'solid-logic'\nimport * as debug from './debug'\nimport { complain, alertDialog, getSameAs, deleteRecursive, deleteThingAndDoc, compareForSort, nameFor } from './localUtils'\nimport { groupMembership } from './groupMembershipControl'\n\nconst ns = UI.ns\nconst utils = UI.utils\nconst kb = store\nlet dom\nlet selectedGroups = {}\nlet selectedPeople = {}\nlet ulPeople = null\nlet ulGroups = null\nlet searchInput = null\nlet cardMain = null\nlet book = null\nlet dataBrowserContext = null\nlet onGroupButtonClick = null\n\n// ######## Group presenter\n\nexport function setActiveGroupButton (groupsUl, activeBtn) {\n groupsUl.querySelectorAll('button').forEach(btn => {\n btn.classList.remove('btn-primary', 'allGroupsButton--selected', 'allGroupsButton--active', 'allGroupsButton--loaded')\n btn.classList.add('btn-secondary')\n })\n if (activeBtn) {\n activeBtn.classList.remove('btn-secondary')\n activeBtn.classList.add('btn-primary')\n }\n}\n\nexport function renderGroupButtons (currentBook, groupsUl, options, domElement, groupsSelected, peopleUl, searchEl, cardMainEl, context, groupClickCallback) {\n dom = domElement\n selectedGroups = groupsSelected || {}\n if (peopleUl) ulPeople = peopleUl\n if (searchEl) searchInput = searchEl\n if (cardMainEl) cardMain = cardMainEl\n if (context) dataBrowserContext = context\n if (groupClickCallback) onGroupButtonClick = groupClickCallback\n book = currentBook\n ulGroups = groupsUl\n const groups = groupsInOrder(book, options)\n utils.syncTableToArrayReOrdered(ulGroups, groups, renderGroupLi)\n}\n\n/** Create the common DOM structure for a group list item (li + button).\n * Returns { groupLi, groupButton, name } so callers can attach their own handlers.\n */\nexport function createGroupLi (group) {\n const name = kb.any(group, ns.vcard('fn'))\n const groupLi = dom.createElement('li')\n groupLi.setAttribute('role', 'listitem')\n groupLi.setAttribute('aria-label', name ? name.value : 'Some group')\n groupLi.subject = group\n UI.widgets.makeDraggable(groupLi, group)\n\n const groupButton = groupLi.appendChild(dom.createElement('button'))\n groupButton.setAttribute('type', 'button')\n groupButton.innerHTML = name ? name.value : 'Some group'\n groupButton.classList.add('allGroupsButton', 'actionButton', 'btn-secondary', 'action-button-focus')\n\n return { groupLi, groupButton, name }\n}\n\nexport async function handleURIsDroppedOnGroup (uris, group) {\n for (const u of uris) {\n let thing = kb.sym(u)\n try {\n thing = await addPersonToGroup(thing, group)\n } catch (_e) {\n const msg = 'Error adding to group. Make sure you are adding a contact URI.'\n alertDialog(msg)\n }\n if (thing) refreshNames(ulPeople)\n }\n}\n\nfunction renderGroupLi (group) {\n function groupLiClickListener (event) {\n event.preventDefault()\n setActiveGroupButton(ulGroups, groupButton)\n if (onGroupButtonClick) onGroupButtonClick()\n if (!event.metaKey) {\n for (const key in selectedGroups) delete selectedGroups[key] // If Command key pressed, accumulate multiple\n }\n selectedGroups[group.uri] = !selectedGroups[group.uri]\n refreshThingsSelected(ulGroups, selectedGroups)\n // Load group members and refresh people list\n kb.fetcher.nowOrWhenFetched(group.doc(), undefined, function (ok, message) {\n if (!ok) {\n debug.error('Cannot load one group: ' + group + '. Stack: ' + message)\n }\n refreshNames(ulPeople, null, false)\n })\n }\n\n const { groupLi, groupButton } = createGroupLi(group)\n\n groupButton.addEventListener('click', groupLiClickListener, false)\n UI.widgets.makeDropTarget(groupLi, uris => handleURIsDroppedOnGroup(uris, group))\n groupLi.addEventListener('click', groupLiClickListener, true)\n return groupLi\n} // renderGroupLi\n\nexport function selectAllGroups (\n selectedGroups,\n ulGroups,\n callbackFunction\n) {\n function fetchGroupAndSelect (group, groupLi) {\n return new Promise((resolve, reject) => {\n groupLi.classList.add('group-loading')\n groupLi.setAttribute('aria-busy', 'true')\n kb.fetcher.nowOrWhenFetched(group.doc(), undefined, function (\n ok,\n message\n ) {\n if (!ok) {\n const msg = 'Cannot load group ' + group + '. Stack: ' + message\n debug.error(msg)\n if (callbackFunction) callbackFunction(false, msg)\n reject(msg)\n return\n }\n groupLi.classList.remove('group-loading')\n groupLi.setAttribute('aria-busy', 'false')\n groupLi.classList.add('selected')\n selectedGroups[group.uri] = true\n refreshThingsSelected(ulGroups, selectedGroups)\n refreshNames(ulPeople, null) // @@ every time??\n if (callbackFunction) callbackFunction(true)\n resolve(true)\n })\n })\n }\n\n for (let k = 0; k < ulGroups.children.length; k++) {\n const groupLi = ulGroups.children[k]\n const group = groupLi.subject\n if (!group) continue // Skip non-group items (e.g. All contacts, New group)\n fetchGroupAndSelect(group, groupLi)\n .catch(err => {\n if (callbackFunction) callbackFunction(false, err)\n })\n } // for each row\n}\n\nexport function refreshThingsSelected (ul, selectionArray) {\n for (let i = 0; i < ul.children.length; i++) {\n const li = ul.children[i]\n if (li.subject) {\n li.classList.toggle('selected', !!selectionArray[li.subject.uri])\n }\n }\n}\n\nexport function syncGroupUl (book, options, groupsUl, domElement, groupsSelected, peopleUl, searchEl) {\n dom = domElement\n if (groupsSelected) selectedGroups = groupsSelected\n if (peopleUl) ulPeople = peopleUl\n if (searchEl) searchInput = searchEl\n ulGroups = groupsUl\n const groups = groupsInOrder(book, options)\n if (groups.length > 0) {\n renderGroupLi(groups[0]) // pre-render one to get the style right, then throw it away\n }\n utils.syncTableToArrayReOrdered(groupsUl, groups, renderGroupLi)\n // refreshThingsSelected(groupsUl, selectedGroups)\n}\n\nfunction groupsInOrder (book, options) {\n let sortMe = []\n if (options.foreignGroup) {\n sortMe.push([\n '',\n kb.any(options.foreignGroup, ns.vcard('fn')),\n options.foreignGroup\n ])\n }\n if (book) {\n const groupIndex = kb.any(book, ns.vcard('groupIndex'))\n const gs = book ? kb.each(book, ns.vcard('includesGroup'), null, groupIndex) : []\n const gs2 = gs.map(function (g) {\n return [book, kb.any(g, ns.vcard('fn')), g]\n })\n sortMe = sortMe.concat(gs2)\n sortMe.sort()\n }\n return sortMe.map(tuple => tuple[2])\n}\n\nexport async function loadAllGroups (book) {\n const groupIndex = kb.any(book, ns.vcard('groupIndex'))\n if (groupIndex) {\n await kb.fetcher.load(groupIndex)\n const gs = book ? kb.each(book, ns.vcard('includesGroup'), null, groupIndex) : []\n await kb.fetcher.load(gs)\n return gs\n } else {\n return [] // no groups\n }\n}\n\n// The book could be the main subject, or linked from a group we are dealing with\nexport function findBookFromGroups (book) {\n if (book) {\n return book\n }\n let g\n for (const gu in selectedGroups) {\n g = kb.sym(gu)\n const b = kb.any(undefined, ns.vcard('includesGroup'), g)\n if (b) return b\n }\n throw new Error(\n 'findBookFromGroups: Cant find address book which this group is part of'\n )\n}\n// ######## Group presenter - END\n\n// ######## Person presenter\n/** Refresh the list of names */\nexport function refreshNames (ulPeopleArg, detailsView, autoSelect = true) {\n // If the caller did not explicitly pass a list element, fall back to the\n // global variable that other helpers (renderGroupButtons, syncGroupUl, etc.)\n // keep up to date. This allows callers that don't have easy access to the\n // element to simply invoke `refreshNames()` and get the behaviour they\n // expect when the address-book UI is present.\n const ul = ulPeopleArg || ulPeople\n\n // Guard: ul must be a DOM element with children. Callers sometimes pass the\n // wrong thing (e.g. a person object) which leads to the\n // \"Cannot read properties of undefined (reading 'length')\" error in\n // syncTableToArrayReOrdered. Bail out early if the value is not valid.\n if (!ul || !ul.children || typeof ul.children.length !== 'number') {\n debug.warn('refreshNames called with invalid ulPeople:', ul)\n return\n }\n\n function setPersonListener (personLi, person) {\n function handleSelect (event) {\n event.preventDefault()\n selectPerson(ul, person, cardMain)\n }\n personLi.addEventListener('click', handleSelect)\n personLi.addEventListener('keydown', function (event) {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n handleSelect(event)\n }\n })\n }\n\n let cards = []\n const groups = Object.keys(selectedGroups).map(groupURI => kb.sym(groupURI))\n groups.forEach(group => {\n if (selectedGroups[group.value]) {\n cards = cards.concat(groupMembers(kb, group))\n }\n })\n cards.sort(compareForSort) // @@ sort by name not UID later\n for (let k = 0; k < cards.length - 1;) {\n if (cards[k].uri === cards[k + 1].uri) {\n cards.splice(k, 1) // Eliminate duplicates from more than one group\n } else {\n k++\n }\n }\n\n function renderNameInGroupList (person, ul) {\n const personLi = dom.createElement('li')\n personLi.setAttribute('role', 'listitem')\n personLi.setAttribute('tabindex', '0')\n personLi.classList.add('personLi')\n personLi.subject = person\n UI.widgets.makeDraggable(personLi, person)\n\n // Container for the row\n const rowDiv = dom.createElement('div')\n rowDiv.classList.add('personLi-row')\n\n // Left: Avatar\n const avatarDiv = dom.createElement('div')\n avatarDiv.classList.add('personLi-avatar')\n // Placeholder avatar (shown initially while person doc loads)\n const placeholderEl = dom.createElement('div')\n placeholderEl.classList.add('avatar-placeholder')\n placeholderEl.innerHTML = '<svg aria-hidden=\"true\" width=\"36\" height=\"36\" viewBox=\"0 0 36 36\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><circle cx=\"18\" cy=\"18\" r=\"18\" fill=\"#e0e0e0\"/><text x=\"50%\" y=\"58%\" text-anchor=\"middle\" fill=\"#595959\" font-size=\"16\" font-family=\"Arial\" dy=\".3em\">?</text></svg>'\n avatarDiv.appendChild(placeholderEl)\n\n // Get name early so it can be used in trySetAvatar\n const name = nameFor(person) || 'Unknown Name'\n\n // Try to set avatar from already-loaded data, or fetch the person's doc\n function trySetAvatar () {\n const avatarUrl = kb.any(person, ns.vcard('hasPhoto'))\n if (avatarUrl && avatarUrl.value) {\n const img = dom.createElement('img')\n img.src = avatarUrl.value\n img.alt = name + ' avatar'\n avatarDiv.replaceChild(img, avatarDiv.firstChild)\n }\n }\n trySetAvatar() // check if already in store\n\n // Load person's own document in background to get hasPhoto\n kb.fetcher.nowOrWhenFetched(person.doc(), undefined, function (ok, message) {\n if (!ok) {\n debug.error('Cannot load contact: ' + person + '. Stack: ' + message)\n personLi.classList.add('personLi--error')\n return // skip avatar – doc is unavailable\n }\n trySetAvatar()\n })\n\n // Center: Name\n const infoDiv = dom.createElement('div')\n infoDiv.classList.add('personLi-info')\n\n personLi.setAttribute('aria-label', name)\n const nameDiv = dom.createElement('div')\n nameDiv.classList.add('personLi-name')\n nameDiv.textContent = name\n\n infoDiv.appendChild(nameDiv)\n\n // Right: Arrow icon\n const arrowDiv = dom.createElement('div')\n arrowDiv.classList.add('personLi-arrow')\n arrowDiv.innerHTML = '<svg aria-hidden=\"true\" width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M6 4.5L11.25 9L6 13.5\" stroke=\"#595959\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'\n\n // Assemble\n rowDiv.appendChild(avatarDiv)\n rowDiv.appendChild(infoDiv)\n rowDiv.appendChild(arrowDiv)\n personLi.appendChild(rowDiv)\n\n setPersonListener(personLi, person)\n return personLi\n }\n\n utils.syncTableToArrayReOrdered(ul, cards, person => renderNameInGroupList(person, ul))\n refreshFilteredPeople(ul, autoSelect, detailsView || cardMain)\n} // refreshNames\n\nexport function selectPerson (ulPeople, person, detailsView) {\n if (!detailsView) return\n if (detailsView.parentNode) detailsView.parentNode.classList.remove('hidden')\n detailsView.innerHTML = 'Loading...'\n detailsView.setAttribute('aria-busy', 'true')\n detailsView.classList.add('detailsSectionContent--wide')\n selectedPeople = {}\n selectedPeople[person.uri] = true\n refreshFilteredPeople(ulPeople, false, detailsView) // Color to remember which one you picked\n let local\n try {\n local = book ? localNode(person) : person\n } catch (err) {\n detailsView.innerHTML = ''\n detailsView.setAttribute('aria-busy', 'false')\n complain(detailsView, dom, 'Cannot load contact: ' + err.message)\n return\n }\n kb.fetcher.nowOrWhenFetched(local.doc(), undefined, function (\n ok,\n message\n ) {\n detailsView.innerHTML = ''\n detailsView.setAttribute('aria-busy', 'false')\n if (!ok) {\n debug.error('Failed to load contact card: ' + local + '. Stack: ' + message)\n complain(detailsView, dom, 'Failed to load contact. If it persists, contact your admin.')\n return\n }\n // debug.log(\"Loaded card \" + local + '\\n')\n\n // Top-right toolbar with link icon and delete button\n const toolbar = dom.createElement('div')\n toolbar.classList.add('contact-toolbar')\n const linkEl = UI.widgets.linkIcon(dom, local)\n linkEl.setAttribute('title', 'Uri of contact')\n toolbar.appendChild(linkEl)\n\n if (authn.currentUser()) {\n // Add in a delete button to delete from AB\n const deleteButton = UI.widgets.deleteButtonWithCheck(\n dom,\n toolbar, // appends it to toolbar.appendChild(deleteButton)\n 'contact',\n async function () {\n const container = person.dir() // ASSUMPTION THAT CARD IS IN ITS OWN DIRECTORY\n\n const pname = kb.any(person, ns.vcard('fn'))\n debug.log('We are about to delete the contact ' + pname)\n await loadAllGroups() // need to wait for all groups to be loaded in case they have a link to this person\n // load people.ttl\n const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))\n await kb.fetcher.load(nameEmailIndex)\n\n // - delete person's WebID's in each Group\n // - delete the references to it in group files and save them back\n // - delete the reference in people.ttl and save it back\n\n // find all Groups\n const groups = groupMembership(person)\n let removeFromGroups = []\n // find person WebID's\n groups.forEach(group => {\n const webids = getSameAs(kb, person, group.doc())\n // for each check in each Group that it is not used by an other person then delete\n webids.forEach(webid => {\n if (getSameAs(kb, webid, group.doc()).length === 1) {\n removeFromGroups = removeFromGroups.concat(kb.statementsMatching(group, ns.vcard('hasMember'), webid, group.doc()))\n }\n })\n })\n\n // Only if folder deletion succeeds, proceed with person deletion\n await kb.updater.updateMany(removeFromGroups)\n\n try {\n await deleteThingAndDoc(person)\n } catch (err) {\n complain(detailsView, dom, 'Failed to delete contact. If it persists, contact your admin.')\n return\n }\n\n try {\n await deleteRecursive(kb, container, toolbar, dom)\n } catch (err) {\n const msg = 'Failed to delete contact. If it persists, contact your admin.'\n complain(detailsView, dom, msg)\n return\n }\n refreshNames(ulPeople, detailsView)\n detailsView.innerHTML = 'Contact data deleted.'\n }\n )\n deleteButton.classList.add('deleteButton')\n }\n detailsView.appendChild(toolbar)\n\n detailsView.classList.add('detailsSectionContent--wide')\n detailsView.appendChild(renderPane(local, 'contact'))\n })\n}\n\nexport function deselectAllPeople (ulPeople) {\n selectedPeople = {}\n if (ulPeople) {\n for (let i = 0; i < ulPeople.children.length; i++) {\n ulPeople.children[i].classList.remove('selected')\n }\n }\n}\n\nexport function refreshFilteredPeople (ulPeople, active, detailsView) {\n let count = 0\n let lastRow = null\n for (let i = 0; i < ulPeople.children.length; i++) {\n const liElement = ulPeople.children[i]\n const matches = filterName(nameFor(liElement.subject))\n if (matches) {\n count++\n lastRow = liElement\n }\n liElement.classList.toggle('selected', matches && !!selectedPeople[liElement.subject.uri])\n liElement.classList.toggle('hidden', !matches)\n }\n if (count === 1 && active) {\n const unique = lastRow.subject\n selectPerson(ulPeople, unique, detailsView)\n }\n}\n\nfunction filterName (name) {\n const filter = searchInput.value.trim().toLowerCase()\n if (filter.length === 0) return true\n const parts = filter.split(' ') // Each name part must be somewhere\n for (let j = 0; j < parts.length; j++) {\n const word = parts[j]\n if (name.toLowerCase().indexOf(word) < 0) return false\n }\n return true\n}\n\nfunction renderPane (subject, paneName) {\n const p = dataBrowserContext.session.paneRegistry.byName(paneName)\n const d = p.render(subject, dataBrowserContext)\n d.classList.add('renderPane')\n return d\n}\n\nfunction localNode (person) {\n const aliases = kb.allAliases(person)\n const prefix = book.dir().uri\n for (let i = 0; i < aliases.length; i++) {\n if (aliases[i].uri.slice(0, prefix.length) === prefix) {\n return aliases[i]\n }\n }\n throw new Error('No local URI for ' + person)\n}\n\n// Check every group is in the list and add it if not.\nexport async function checkDataModel (book, detailsSectionContent) {\n // await kb.fetcher.load(groups) // asssume loaded already\n const groups = await loadAllGroups(book)\n\n if (groups && groups.length > 0) {\n const { del, ins } = await getDataModelIssues(groups)\n\n if (authn.currentUser()) {\n if (del.length) {\n UI.widgets.deleteButtonWithCheck(\n dom,\n detailsSectionContent, // where it appends it to\n 'contact',\n async function () {\n await kb.updater.updateMany(del, ins)\n debug.log('Deleted ' + del.length + ' bad statements from groups')\n })\n }\n }\n }\n}\n\n// Prepare book data once so askName forms load instantly\nexport async function ensureBookLoaded () {\n const ourBook = findBookFromGroups(book)\n try {\n await kb.fetcher.load(ourBook)\n } catch (err) {\n throw new Error('Book won\\'t load:' + ourBook)\n }\n const nameEmailIndex = kb.any(ourBook, ns.vcard('nameEmailIndex'))\n if (!nameEmailIndex) throw new Error('No nameEmailIndex')\n await kb.fetcher.load(nameEmailIndex)\n}\n","// Render a control to record the group memberships we have for this agent\nimport * as UI from 'solid-ui'\nimport { store, authn } from 'solid-logic'\nimport './styles/groupMembership.css'\nimport * as debug from './debug'\nimport { normalizeGroupUri, confirmDialog, alertDialog } from './localUtils'\nimport { refreshNames } from './addressBookPresenter'\nimport { vcardWebIDs } from './webidControl'\n\nconst ns = UI.ns\nconst kb = store\n\n// Groups the person is a member of\nexport function groupMembership (person, store = kb) {\n let groups = store.statementsMatching(null, ns.owl('sameAs'), person).map(st => st.why)\n .concat(store.each(null, ns.vcard('hasMember'), person))\n const strings = new Set(groups.map(group => normalizeGroupUri(group.uri))) // remove dups with normalized URIs\n groups = [...strings].map(uri => store.sym(uri))\n return groups\n}\n\n/**\n * Render the group membership section for a given person.\n *\n * @param person - the contact whose memberships are being edited\n * @param context - the Data Browser context used by the pane registry\n * @param ulPeople - **optional** the `<ul>` element containing the master\n * people list. When provided (e.g. by the contacts pane) the control will\n * automatically call `refreshNames(ulPeople)` after removing a membership so\n * that the list on the left reflects the change. If `null` this behaviour\n * is skipped.\n */\nexport async function renderGroupMemberships (person, context, ulPeople) {\n // keep a reference to the people list (if any) so callers can ask us to\n // refresh it when group membership changes. The callers that render an\n // address-book view pass their `ulPeople` element; other consumers may not\n // have one and can simply ignore it.\n const peopleUl = ulPeople || null\n\n // Remove a person from a group\n async function removeFromGroup (person, group) {\n const pname = kb.any(person, ns.vcard('fn'))\n const gname = kb.any(group, ns.vcard('fn'))\n // find all WebIDs of thing\n const thingwebids = kb.each(null, ns.owl('sameAs'), person, group.doc())\n // WebID can be deleted only if not used in another thing\n let webids = []\n thingwebids.forEach(webid => {\n if (kb.statementsMatching(webid, ns.owl('sameAs'), person, group.doc())) webids = webids.concat(webid)\n })\n webids = vcardWebIDs(kb, person).map(webid => webid.value)\n // When checking how many groups this entity belongs to we should look\n // at the person **and** any of their webID nodes. Build an array of\n // named nodes so we can query all of them.\n const webidNodes = webids.map(u => kb.sym(u))\n const members = [person].concat(webidNodes)\n // collect all groups for any of these members, dedupe by URI\n let groups = members\n .flatMap(m => kb.each(null, ns.vcard('hasMember'), m))\n groups = [...new Set(groups.map(g => g.uri))].map(u => kb.sym(u))\n if (groups.length < 2) {\n alertDialog(\n 'Must be a member of at least one group. Add to another group first.'\n )\n return\n }\n const message = 'Remove ' + pname + ' from group ' + gname + '?'\n if (await confirmDialog(message)) {\n let del = kb\n .statementsMatching(person, undefined, undefined, group.doc())\n .concat(kb.statementsMatching(undefined, undefined, person, group.doc()))\n webids.forEach(webid => {\n if (kb.statementsMatching(webid, ns.owl('sameAs'), undefined, group.doc()).length < 2) {\n del = del.concat(kb.statementsMatching(undefined, undefined, webid, group.doc()))\n }\n })\n try {\n await kb.updater.update(del, [])\n } catch (err) {\n const message = 'Error removing member from group ' + group + ': ' + err\n container.appendChild(UI.widgets.errorMessageBlock(dom, message, 'pink'))\n return\n }\n debug.log('Removed ' + pname + ' from group ' + gname)\n // to allow refresh of card groupList\n kb.fetcher.unload(group.doc())\n await kb.fetcher.load(group.doc())\n syncGroupPills()\n // also update the people list if one exists (or via global fallback)\n refreshNames(peopleUl)\n }\n }\n\n function createGroupItem (group) {\n const gname = kb.any(group, ns.vcard('fn'))\n const label = gname ? gname.value : group.uri\n\n const li = dom.createElement('li')\n li.classList.add('group-membership-item')\n\n // Main group button\n const btn = dom.createElement('button')\n btn.setAttribute('type', 'button')\n btn.classList.add('allGroupsButton', 'actionButton', 'btn-secondary', 'action-button-focus')\n btn.textContent = label\n btn.title = label\n li.appendChild(btn)\n\n // Toolbar below the button: link icon + delete button\n const toolbar = dom.createElement('div')\n toolbar.classList.add('group-membership-toolbar')\n\n // Link icon\n const linkEl = UI.widgets.linkIcon(dom, group)\n linkEl.setAttribute('title', 'Link to ' + label)\n toolbar.appendChild(linkEl)\n\n if (authn.currentUser()) {\n // Delete button\n UI.widgets.deleteButtonWithCheck(\n dom,\n toolbar,\n 'membership in ' + label,\n async function () {\n // async operation handles its own refresh once the group doc has\n // been reloaded\n await removeFromGroup(person, group)\n }\n )\n }\n\n li.appendChild(toolbar)\n return li\n }\n\n function syncGroupPills (groups = null) {\n // Clear previous render so we don't keep appending duplicate headers / lists\n container.innerHTML = ''\n\n const header = dom.createElement('h3')\n header.classList.add('group-membership-header')\n header.textContent = 'Part of groups'\n container.appendChild(header)\n\n const pillsWrapper = dom.createElement('ul')\n pillsWrapper.classList.add('group-pills-wrapper')\n container.appendChild(pillsWrapper)\n\n groups = groups || groupMembership(person, kb)\n\n if (groups.length === 0) {\n pillsWrapper.innerHTML = '<span>Not part of any Address Book group.</span>'\n } else {\n pillsWrapper.innerHTML = ''\n }\n\n groups.forEach(group => {\n pillsWrapper.appendChild(createGroupItem(group))\n })\n }\n\n async function loadGroupsFromBook (book = null) {\n if (!book) {\n book = kb.any(undefined, ns.vcard('includesGroup'))\n if (!book) {\n return [] // no book => no groups\n }\n }\n const groupIndex = kb.any(book, ns.vcard('groupIndex'))\n const gs = book ? kb.each(book, ns.vcard('includesGroup'), null, groupIndex) : []\n await kb.fetcher.load(gs)\n return gs\n }\n\n const { dom } = context\n const kb = context.session.store\n\n const container = dom.createElement('div')\n container.classList.add('group-membership-container')\n\n // find book any group and load all groups (so membership checks have the data they need)\n await loadGroupsFromBook()\n\n // renders the Part of Group\n container.refresh = syncGroupPills\n syncGroupPills()\n return container\n}\n","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./individual.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./individual.css\";\n export default content && content.locals ? content.locals : undefined;\n","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./contactsRDFFormsEnforced.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./contactsRDFFormsEnforced.css\";\n export default content && content.locals ? content.locals : undefined;\n","import { sym, Namespace, parse } from 'rdflib'\nimport { widgets } from 'solid-ui'\n\nconst baseUri = 'https://solidos.github.io/contacts-pane/src/ontology/'\n\nexport function renderForm (\n div,\n subject, // Represents the RDF that fills the form\n formSource, // The imported form Turtle source\n formName, // The name of the form file (e.g., 'socialMedia.ttl')\n store,\n dom,\n editableProfile,\n whichForm) {\n // --- Form resource setup ---\n const formUri = baseUri + formName // Full URI to the form file\n const exactForm = whichForm || 'this' // If there are more 'a ui:Form' elements in a form file\n const formThis = Namespace(formUri + '#')(exactForm) // NamedNode for #this in the form\n\n loadDocument(store, formSource, formName, formUri)\n\n widgets.appendForm(\n dom,\n div,\n {},\n subject,\n formThis,\n editableProfile,\n (ok, mes) => {\n if (!ok) widgets.errorMessageBlock(dom, mes)\n }\n )\n} // renderForm\n\n// we need to load into the store some additional information about Social Media accounts\nexport function loadDocument (\n store,\n documentSource,\n documentName,\n documentURI\n) {\n const finalDocumentUri = documentURI || baseUri + documentName // Full URI to the file\n const document = sym(finalDocumentUri) // rdflib NamedNode for the document\n\n if (!store.holds(undefined, undefined, undefined, document)) {\n // we are using the social media form because it contains the information we need\n // the form can be used for both use cases: create UI for edit and render UI for display\n parse(documentSource, store, finalDocumentUri, 'text/turtle', () => null) // Load doc directly\n }\n}\n","import * as UI from 'solid-ui'\nimport { authn, store } from 'solid-logic'\nimport { renderMugshotGallery } from './mugshotGallery'\nimport { renderWebIdControl, renderPublicIdControl } from './webidControl'\nimport { renderGroupMemberships } from './groupMembershipControl'\nimport formsSource from './ontology/individualAndOrganizationForm.ttl'\nimport VCARD_ONTOLOGY_TEXT from './ontology/vcard.ttl'\nimport './styles/individual.css'\nimport './styles/contactsRDFFormsEnforced.css'\nimport { renderForm, loadDocument } from './rdfFormsHelper'\nimport * as debug from './debug'\nimport { skipLabelsFromTabbing, isAWebID } from './localUtils'\n\nconst ns = UI.ns\nconst kb = store\n\nconst formsName = 'individualAndOrganizationForm.ttl' // The name of the form file\nconst vcardName = 'vcard.ttl' // The name of the vcard file\n\nexport async function renderIndividual (dom, div, subject, dataBrowserContext) {\n const t = kb.findTypeURIs(subject)\n const isOrganization = !!(t[ns.vcard('Organization').uri] || t[ns.schema('Organization').uri])\n const editable = kb.updater.editable(subject.doc().uri, kb)\n\n // We load the local form document\n loadDocument(kb, formsSource, formsName)\n\n // We need to make sure VCARD ontology is loaded in the store\n const vcardOntUri = UI.ns.vcard('Type').doc().uri // URI to VCARD\n loadDocument(kb, VCARD_ONTOLOGY_TEXT, vcardName, vcardOntUri)\n\n try {\n await kb.fetcher.load(subject.doc())\n } catch (err) {\n debug.error('Error loading profile card. Stack: ' + err)\n throw new Error('Failed to load profile card.')\n } // end of try catch on load\n\n div.classList.add('individualPane')\n\n authn.checkUser() // kick off async operation @@@ use async version\n\n div.appendChild(renderMugshotGallery(dom, subject))\n\n const whichForm = isOrganization ? 'organizationForm' : 'individualForm'\n\n renderForm(div, subject, formsSource, formsName, store, dom, subject.doc(), whichForm)\n // Improve keyboard navigation: prevent tabbing into label links created by rdflib/solid-ui forms\n skipLabelsFromTabbing(div)\n\n // forward list element from context if available; some callers (such as\n // the contacts pane) attach `ulPeople` so that group membership control can\n // refresh the master list when a membership is removed.\n if (!isAWebID(subject)) {\n div.appendChild(await renderGroupMemberships(\n subject,\n dataBrowserContext,\n dataBrowserContext.ulPeople\n ))\n }\n\n if (authn.currentUser()) {\n // Allow to attach documents etc to the profile card\n // creates a\n const h3 = div.appendChild(dom.createElement('h3'))\n h3.textContent = 'Attach a link to any file'\n h3.classList.add('contactPanedHeading')\n\n UI.widgets.attachmentList(dom, subject, div, {\n modify: editable\n // promptIcon: UI.icons.iconBase + 'noun_681601.svg',\n // predicate: default <http://www.w3.org/2005/01/wf/flow#attachment>\n })\n }\n\n if (isOrganization) {\n div.appendChild(await renderPublicIdControl(subject, dataBrowserContext))\n } else if (!isAWebID(subject)) {\n // Only render WebID control for a contact and not. WebID.\n div.appendChild(await renderWebIdControl(subject, dataBrowserContext))\n }\n} // renderIndividual\n","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./toolsPane.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./toolsPane.css\";\n export default content && content.locals ? content.locals : undefined;\n","// The tools pane is for managing and debugging and maintaining solid contacts databases\nimport * as UI from 'solid-ui'\nimport { store } from 'solid-logic'\nimport { saveNewGroup, addPersonToGroup, groupMembers } from './contactLogic'\nimport './styles/toolsPane.css'\nimport * as $rdf from 'rdflib'\nimport { normalizeGroupUri } from './localUtils'\nimport * as debug from './debug'\n\nconst kb = store\nconst ns = UI.ns\nconst VCARD = ns.vcard\n\nlet book\nlet selectedGroups\nlet logSpace\nlet refreshGroupsFn\n\nexport function toolsPane (\n selectAllGroups,\n selectedGroupsParam,\n groupsMainTable,\n bookParam,\n dataBrowserContext,\n me,\n refreshGroups\n) {\n book = bookParam\n selectedGroups = selectedGroupsParam\n refreshGroupsFn = refreshGroups\n const dom = dataBrowserContext.dom\n\n const pane = dom.createElement('div')\n pane.classList.add('toolsPane')\n\n const settingsHeader = dom.createElement('h3')\n settingsHeader.textContent = 'Tools'\n pane.appendChild(settingsHeader)\n\n const divStatistics = pane.appendChild(dom.createElement('div'))\n divStatistics.classList.add('statsLog')\n\n logSpace = divStatistics.appendChild(dom.createElement('pre'))\n logSpace.setAttribute('id', 'logSpace')\n\n const buttonsContainer = pane.appendChild(dom.createElement('div'))\n buttonsContainer.classList.add('toolsButtonsContainer')\n\n function setActiveButton (activeBtn) {\n const wasActive = activeBtn.classList.contains('btn-primary')\n buttonsContainer.querySelectorAll('button').forEach(btn => {\n btn.classList.remove('btn-primary', 'toolsButton--loading', 'toolsButton--error', 'toolsButton--success')\n btn.classList.add('btn-secondary')\n })\n if (!wasActive) {\n activeBtn.classList.remove('btn-secondary')\n activeBtn.classList.add('btn-primary')\n }\n }\n\n const loadIndexButton = buttonsContainer.appendChild(dom.createElement('button'))\n loadIndexButton.textContent = 'Load main index'\n loadIndexButton.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n loadIndexButton.addEventListener('click', () => {\n setActiveButton(loadIndexButton)\n logSpace.textContent = ''\n loadIndexHandler(loadIndexButton, logSpace)\n })\n\n const statButton = buttonsContainer.appendChild(dom.createElement('button'))\n statButton.textContent = 'Statistics'\n statButton.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n statButton.addEventListener('click', () => {\n setActiveButton(statButton)\n logSpace.textContent = ''\n stats(logSpace)\n })\n\n const checkAccessButton = buttonsContainer.appendChild(dom.createElement('button'))\n checkAccessButton.textContent =\n 'Check individual contact access of selected groups'\n checkAccessButton.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n checkAccessButton.addEventListener('click', (event) => {\n setActiveButton(checkAccessButton)\n logSpace.textContent = ''\n checkAcces(event)\n })\n\n // DUPLICATES CHECK\n const checkDuplicates = buttonsContainer.appendChild(dom.createElement('button'))\n checkDuplicates.textContent = 'Find duplicate contacts'\n checkDuplicates.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n checkDuplicates.addEventListener('click', function (_event) {\n setActiveButton(checkDuplicates)\n logSpace.textContent = ''\n const stats = {} // global god context\n\n stats.book = book\n stats.nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))\n log(logSpace, 'Loading name index...')\n\n store.fetcher.nowOrWhenFetched(\n stats.nameEmailIndex,\n undefined,\n function (_ok, _message) {\n log(logSpace, 'Loaded name index.')\n\n stats.cards = []\n stats.duplicates = []\n stats.definitive = []\n stats.nameless = []\n\n stats.exactDuplicates = []\n stats.nameOnlyDuplicates = []\n\n stats.uniquesSet = []\n stats.groupProblems = []\n\n // Erase one card and all its files -> (err)\n //\n /*\n function eraseOne (card) {\n return new Promise(function (resolve, reject) {\n function removeFromMainIndex () {\n var indexBit = kb.connectedStatements(card, stats.nameEmailIndex)\n log(logSpace, 'Bits of the name index file:' + indexBit)\n log(logSpace, 'Patching main index file...')\n kb.updater.update(indexBit, [], function (uri, ok, body) {\n if (ok) {\n log(logSpace, 'Success')\n resolve(null)\n } else {\n log(logSpace, 'Error patching index file! ' + body)\n reject('Error patching index file! ' + body)\n }\n })\n }\n var filesToDelete = [ card.doc() ]\n var photos = kb.each(card, ns.vcard('hasPhoto')) // could be > 1\n if (photos.length) {\n filesToDelete = filesToDelete.concat(photos)\n }\n filesToDelete.push(card.dir()) // the folder last\n log(logSpace, 'Files to delete: ' + filesToDelete)\n if (!await confirmDialog('DELETE card ' + card.dir() + ' for \"' + kb.any(card, VCARD('fn')) + '\", with ' + kb.each(card).length + 'statements?')) {\n return resolve('Cancelled by user')\n }\n\n function deleteNextFile () {\n var resource = filesToDelete.shift()\n if (!resource) {\n log(logSpace, 'All deleted')\n removeFromMainIndex()\n resolve()\n }\n log(logSpace, 'Deleting ... ' + resource)\n kb.fetcher.delete(resource)\n .then(function () {\n log(logSpace, 'Deleted ok: ' + resource)\n deleteNextFile()\n })\n .catch(function (e) {\n var err = '*** ERROR deleting ' + resource + ': ' + e\n log(logSpace, err)\n if (await confirmDialog('Patch out index file for card ' + card.dir() + ' EVEN THOUGH card DELETE errors?')) {\n removeFromMainIndex()\n } else {\n reject(err)\n }\n })\n }\n deleteNextFile()\n }) // Promise\n } // erase one\n*/\n // Check actual records to see which are exact matches - slow\n stats.nameDupLog = kb.sym(book.dir().uri + 'dedup-nameDupLog.ttl')\n stats.exactDupLog = kb.sym(book.dir().uri + 'dedup-exactDupLog.ttl')\n /*\n function checkOne (card) {\n return new Promise(function (resolve, reject) {\n var name = kb.anyValue(card, ns.vcard('fn'))\n var other = stats.definitive[name]\n kb.fetcher.load([card, other]).then(function (xhrs) {\n var exclude = {}\n exclude[ns.vcard('hasUID').uri] = true\n exclude[ns.dc('created').uri] = true\n exclude[ns.dc('modified').uri] = true\n function filtered (x) {\n return kb.statementsMatching(null, null, null, x.doc()).filter(function (st) {\n return !exclude[st.predicate.uri]\n })\n }\n var desc = filtered(card)\n var desc2 = filtered(other)\n // var desc = connectedStatements(card, card.doc(), exclude)\n // var desc2 = connectedStatements(other, other.doc(), exclude)\n if (desc.length !== desc2.length) {\n log(logSpace, 'CARDS to NOT match lengths ')\n stats.nameOnlyDuplicates.push(card)\n return resolve(false)\n }\n if (!desc.length) {\n log(logSpace, '@@@@@@ Zero length ')\n stats.nameOnlyDuplicates.push(card)\n return resolve(false)\n }\n // //////// Compare the two\n // Cheat: serialize and compare\n // var cardText = $rdf.serialize(card.doc(), kb, card.doc().uri, 'text/turtle')\n // var otherText = $rdf.serialize(other.doc(), kb, other.doc().uri, 'text/turtle')\n var cardText = (new $rdf.Serializer(kb)).setBase(card.doc().uri).statementsToN3(desc)\n var otherText = (new $rdf.Serializer(kb)).setBase(other.doc().uri).statementsToN3(desc2)\n //\n // log('Name: ' + name + ', statements: ' + desc.length)\n // log('___________________________________________')\n // log('KEEPING: ' + other.doc() + '\\n' + cardText)\n // log('___________________________________________')\n // log('DELETING: '+ card.doc() + '\\n' + otherText)\n // log('___________________________________________')\n //\n if (cardText !== otherText) {\n log(logSpace, 'Texts differ')\n stats.nameOnlyDuplicates.push(card)\n return resolve(false)\n }\n var cardGroups = kb.each(null, ns.vcard('hasMember'), card)\n var otherGroups = kb.each(null, ns.vcard('hasMember'), other)\n for (var j = 0; j < cardGroups.length; j++) {\n var found = false\n for (var k = 0; k < otherGroups.length; k++) {\n if (otherGroups[k].sameTerm(cardGroups[j])) { found = true }\n }\n if (!found) {\n log(logSpace, 'This one groups: ' + cardGroups)\n log(logSpace, 'Other one groups: ' + otherGroups)\n log(logSpace, 'Cant delete this one because it has a group, ' + cardGroups[j] + ', which the other does not.')\n stats.nameOnlyDuplicates.push(card)\n return resolve(false)\n }\n }\n debug.log('Group check done -- exact duplicate: ' + card)\n stats.exactDuplicates.push(card)\n resolve(true)\n }).catch(function (e) {\n log(logSpace, 'Cant load a card! ' + [card, other] + ': ' + e)\n stats.nameOnlyDuplicates.push(card)\n resolve(false)\n // if (await confirmDialog('Patch out index file for card ' + card.dir() + ' EVEN THOUGH card READ errors?')){\n // removeFromMainIndex()\n // }\n })\n })\n } // checkOne\n*/\n stats.nameOnlyErrors = []\n stats.nameLessZeroData = []\n stats.nameLessIndex = []\n stats.namelessUniques = []\n stats.nameOnlyDuplicatesGroupDiff = []\n\n function checkOneNameless (card) {\n return new Promise(function (resolve) {\n kb.fetcher\n .load(card)\n .then(function (_xhr) {\n log(logSpace, ' Nameless check ' + card)\n const exclude = {}\n exclude[ns.vcard('hasUID').uri] = true\n exclude[ns.dc('created').uri] = true\n exclude[ns.dc('modified').uri] = true\n function filtered (x) {\n return kb\n .statementsMatching(null, null, null, x.doc())\n .filter(function (st) {\n return !exclude[st.predicate.uri]\n })\n }\n\n const desc = filtered(card)\n // var desc = connectedStatements(card, card.doc(), exclude)\n // var desc2 = connectedStatements(other, other.doc(), exclude)\n if (!desc.length) {\n log(logSpace, ' Zero length ' + card)\n stats.nameLessZeroData.push(card)\n return resolve(false)\n }\n // Compare the two\n // Cheat: serialize and compare\n // var cardText = $rdf.serialize(card.doc(), kb, card.doc().uri, 'text/turtle')\n // var otherText = $rdf.serialize(other.doc(), kb, other.doc().uri, 'text/turtle')\n const cardText = new $rdf.Serializer(kb)\n .setBase(card.doc().uri)\n .statementsToN3(desc)\n const other = stats.nameLessIndex[cardText]\n if (other) {\n log(logSpace, ' Matches with ' + other)\n // alain not sure it works we may need to concat with 'sameAs' group.doc (.map(st => st.why))\n const cardGroups = kb.each(null, ns.vcard('hasMember'), card)\n const otherGroups = kb.each(null, ns.vcard('hasMember'), other)\n for (let j = 0; j < cardGroups.length; j++) {\n let found = false\n for (let k = 0; k < otherGroups.length; k++) {\n if (otherGroups[k].sameTerm(cardGroups[j])) found = true\n }\n if (!found) {\n log(logSpace, 'This one groups: ' + cardGroups)\n log(logSpace, 'Other one groups: ' + otherGroups)\n log(\n logSpace,\n 'Cant skip this one because it has a group, ' +\n cardGroups[j] +\n ', which the other does not.'\n )\n stats.nameOnlyDuplicatesGroupDiff.push(card)\n return resolve(false)\n }\n }\n debug.log('Group check done -- exact duplicate: ' + card)\n } else {\n log(logSpace, 'First nameless like: ' + card.doc())\n log(logSpace, '___________________________________________')\n log(logSpace, cardText)\n log(logSpace, '___________________________________________')\n stats.nameLessIndex[cardText] = card\n stats.namelessUniques.push(card)\n }\n resolve(true)\n })\n .catch(function (e) {\n log(logSpace, 'Cant load a nameless card!: ' + e)\n stats.nameOnlyErrors.push(card)\n resolve(false)\n })\n })\n } // checkOneNameless\n\n function checkAllNameless () {\n stats.namelessToCheck =\n stats.namelessToCheck || stats.nameless.slice()\n log(logSpace, 'Nameless check left: ' + stats.namelessToCheck.length)\n return new Promise(function (resolve) {\n const x = stats.namelessToCheck.shift()\n if (!x) {\n log(logSpace, 'namelessUniques: ' + stats.namelessUniques.length)\n log(logSpace, 'namelessUniques: ' + stats.namelessUniques)\n if (stats.namelessUniques.length > 0) {\n const msg = dom.createElement('p')\n msg.textContent = 'Add all ' + stats.namelessUniques.length + ' nameless contacts to the rescued set?'\n divStatistics.appendChild(msg)\n const confirmButton = UI.widgets.continueButton(dom, function () {\n stats.uniques = stats.uniques.concat(stats.namelessUniques)\n for (let k = 0; k < stats.namelessUniques.length; k++) {\n stats.uniqueSet[stats.namelessUniques[k].uri] = true\n }\n msg.remove()\n confirmButton.remove()\n resolve(true)\n })\n divStatistics.appendChild(confirmButton)\n } else {\n return resolve(true)\n }\n return\n }\n checkOneNameless(x).then(function (exact) {\n log(logSpace, ' Nameless check returns ' + exact)\n checkAllNameless() // loop\n })\n })\n }\n\n function checkGroupMembers () {\n return new Promise(function (resolve) {\n // var inUniques = 0\n log(logSpace, 'Groups loaded')\n for (let i = 0; i < stats.uniques.length; i++) {\n stats.uniquesSet[stats.uniques[i].uri] = true\n }\n stats.groupMembers = []\n kb.each(null, ns.vcard('hasMember'))\n .forEach(group => { stats.groupMembers = stats.groupMembers.concat(groupMembers(kb, group)) })\n log(logSpace, ' Naive group members ' + stats.groupMembers.length)\n stats.groupMemberSet = []\n for (let j = 0; j < stats.groupMembers.length; j++) {\n stats.groupMemberSet[stats.groupMembers[j].uri] =\n stats.groupMembers[j]\n }\n stats.groupMembers2 = []\n for (const g in stats.groupMemberSet) {\n stats.groupMembers2.push(stats.groupMemberSet[g])\n }\n log(logSpace, ' Compact group members ' + stats.groupMembers2.length)\n\n // LINT NOTE: Block below disabled to fix 'no-constant-condition' ESLint error. Restore or refactor if needed.\n /*\n if (false) {\n // Don't inspect as seems groups membership is complete\n for (let i = 0; i < stats.groupMembers.length; i++) {\n const card = stats.groupMembers[i]\n if (stats.uniquesSet[card.uri]) {\n // inUniques += 1\n } else {\n log(logSpace, ' Not in uniques: ' + card)\n stats.groupProblems.push(card)\n if (stats.duplicateSet[card.uri]) {\n log(logSpace, ' ** IN duplicates alas:' + card)\n } else {\n log(logSpace, ' **** WTF?')\n }\n }\n }\n log(logSpace, 'Problem contacts: ' + stats.groupProblems.length)\n }\n */\n resolve(true)\n })\n } // checkGroupMembers\n\n function scanForDuplicates () {\n return new Promise(function (resolve) {\n stats.cards = kb.each(undefined, VCARD('inAddressBook'), stats.book)\n log(logSpace, '' + stats.cards.length + ' total contacts')\n\n let c, card, name\n for (c = 0; c < stats.cards.length; c++) {\n card = stats.cards[c]\n name = kb.anyValue(card, ns.vcard('fn'))\n if (!name) {\n stats.nameless.push(card)\n continue\n }\n if (stats.definitive[name] === card) {\n // pass\n } else if (stats.definitive[name]) {\n const n = stats.duplicates.length\n if (n < 100 || (n < 1000 && n % 10 === 0) || n % 100 === 0) {\n // log('' + n + ') Possible duplicate ' + card + ' of: ' + definitive[name])\n }\n stats.duplicates.push(card)\n } else {\n stats.definitive[name] = card\n }\n }\n\n stats.duplicateSet = []\n for (let i = 0; i < stats.duplicates.length; i++) {\n stats.duplicateSet[stats.duplicates[i].uri] = stats.duplicates[i]\n }\n stats.namelessSet = []\n for (let i = 0; i < stats.nameless.length; i++) {\n stats.namelessSet[stats.nameless[i].uri] = stats.nameless[i]\n }\n stats.uniques = []\n stats.uniqueSet = []\n for (let i = 0; i < stats.cards.length; i++) {\n const uri = stats.cards[i].uri\n if (!stats.duplicateSet[uri] && !stats.namelessSet[uri]) {\n stats.uniques.push(stats.cards[i])\n stats.uniqueSet[uri] = stats.cards[i]\n }\n }\n log(logSpace, 'Uniques: ' + stats.uniques.length)\n\n log(logSpace, '' + stats.nameless.length + ' nameless contacts.')\n log(\n logSpace,\n '' +\n stats.duplicates.length +\n ' name-duplicate contacts, leaving ' +\n (stats.cards.length - stats.duplicates.length)\n )\n resolve(true)\n })\n }\n\n // Save a new clean version\n function saveCleanPeople () {\n let cleanPeople\n\n return Promise.resolve()\n .then(() => {\n cleanPeople = kb.sym(stats.book.dir().uri + 'clean-people.ttl')\n let sts = []\n for (let i = 0; i < stats.uniques.length; i++) {\n sts = sts.concat(\n kb.connectedStatements(stats.uniques[i], stats.nameEmailIndex)\n )\n }\n const sz = new $rdf.Serializer(kb).setBase(stats.nameEmailIndex.uri)\n log(logSpace, 'Serializing index of uniques...')\n const data = sz.statementsToN3(sts)\n\n return kb.fetcher.webOperation('PUT', cleanPeople, {\n data,\n contentType: 'text/turtle'\n })\n })\n .then(function () {\n log(logSpace, 'Done uniques log ' + cleanPeople)\n return true\n })\n .catch(function (e) {\n log(logSpace, 'Error saving uniques: ' + e)\n })\n }\n\n function saveCleanGroup (g) {\n let cleanGroup\n\n return Promise.resolve()\n .then(() => {\n const s = g.uri.replace('/Group/', '/NewGroup/')\n cleanGroup = kb.sym(s)\n let sts = []\n for (let i = 0; i < stats.uniques.length; i++) {\n sts = sts.concat(\n kb.connectedStatements(stats.uniques[i], g.doc())\n )\n }\n const sz = new $rdf.Serializer(kb).setBase(g.uri)\n log(logSpace, ' Regenerating group of uniques...' + cleanGroup)\n const data = sz.statementsToN3(sts)\n\n return kb.fetcher.webOperation('PUT', cleanGroup, {\n data,\n contentType: 'text/turtle'\n })\n })\n .then(() => {\n log(logSpace, ' Done uniques group ' + cleanGroup)\n return true\n })\n .catch(e => {\n log(logSpace, 'Error saving : ' + e)\n })\n }\n\n function saveAllGroups () {\n log(logSpace, 'Saving ALL GROUPS')\n return Promise.all(stats.groupObjects.map(saveCleanGroup))\n }\n\n const getAndSortGroups = function () {\n let groups = []\n if (stats.book) {\n const books = [stats.book]\n books.forEach(function (book) {\n const gs = book ? kb.each(book, ns.vcard('includesGroup')) : []\n const gs2 = gs.map(function (g) {\n return [book, kb.any(g, ns.vcard('fn')), g]\n })\n groups = groups.concat(gs2)\n })\n groups.sort()\n }\n return groups\n }\n const groups = getAndSortGroups() // Needed?\n\n stats.groupObjects = groups.map(gstr => gstr[2])\n log(logSpace, 'Loading ' + stats.groupObjects.length + ' groups... ')\n kb.fetcher\n .load(stats.groupObjects)\n .then(scanForDuplicates)\n .then(checkGroupMembers)\n .then(checkAllNameless)\n .then(saveCleanPeople)\n .then(saveAllGroups)\n .then(function () {\n log(logSpace, 'Done!')\n })\n }\n )\n })\n\n const checkGroupless = buttonsContainer.appendChild(dom.createElement('button'))\n checkGroupless.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n checkGroupless.textContent = 'Find contacts with no group'\n checkGroupless.addEventListener('click', function (_event) {\n setActiveButton(checkGroupless)\n logSpace.textContent = ''\n log(logSpace, 'Loading groups...')\n selectAllGroups(selectedGroups, groupsMainTable, async function (ok, message) {\n if (!ok) {\n log(logSpace, 'Loading all groups failed. If it persists, contact your admin.')\n return\n }\n\n const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))\n try {\n await kb.fetcher.load(nameEmailIndex)\n } catch (e) {\n debug.error('Error loading name index (vcard(nameEmailIndex)). Stack: ' + e)\n log(logSpace, 'Loading name index failed. If it persists, contact your admin.')\n return\n }\n log(logSpace, 'Loaded groups and name index.')\n getGroupless(book)\n log(logSpace, 'Groupless list finished.')\n }) // select all groups then\n })\n\n const fixGrouplessButton = buttonsContainer.appendChild(dom.createElement('button'))\n fixGrouplessButton.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n fixGrouplessButton.textContent = 'Put all individuals with no group in a new group'\n fixGrouplessButton.addEventListener('click', _event => {\n setActiveButton(fixGrouplessButton)\n logSpace.textContent = ''\n fixGroupless(book)\n })\n\n // this is an old not needed anymore fix from https://github.com/SolidOS/contacts-pane/issues/81\n /*\n const fixToOldDataModelButton = buttonsContainer.appendChild(dom.createElement('button'))\n fixToOldDataModelButton.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n fixToOldDataModelButton.textContent = 'Revert groups to old data model'\n fixToOldDataModelButton.addEventListener('click', _event => {\n setActiveButton(fixToOldDataModelButton)\n logSpace.textContent = ''\n fixToOldDataModel(book)\n })\n */\n return pane\n}\n\nasync function checkAcces (_event) {\n function doCard (card) {\n UI.acl.fixIndividualCardACL(card, (msg) => log(logSpace, msg), function (ok, message) {\n if (ok) {\n log(logSpace, 'Success for ' + UI.utils.label(card))\n } else {\n debug.error('Failure for ' + card + ': ' + message)\n log(logSpace, 'Failure for ' + card + ': ' + message)\n }\n })\n }\n const gg = []\n for (const g in selectedGroups) {\n gg.push(g)\n }\n\n for (let i = 0; i < gg.length; i++) {\n const g = kb.sym(gg[i])\n const a = groupMembers(kb, g)\n log(logSpace, UI.utils.label(g) + ': ' + a.length + ' members')\n for (let j = 0; j < a.length; j++) {\n const card = a[j]\n log(logSpace, UI.utils.label(card))\n doCard(card)\n }\n }\n}\n\nfunction log (logSpace, message) {\n logSpace.textContent += message + '\\n'\n}\n\nfunction stats (logSpace) {\n const totalContacts = kb.each(undefined, VCARD('inAddressBook'), book).length\n log(logSpace, '' + totalContacts + ' contacts loaded. ')\n let groups = kb.each(book, VCARD('includesGroup'))\n const strings = new Set(groups.map(group => normalizeGroupUri(group.uri))) // remove dups with normalized URIs\n groups = [...strings].map(uri => kb.sym(uri))\n log(logSpace, '' + groups.length + ' total groups. ')\n const gg = []\n for (const g in selectedGroups) {\n gg.push(g)\n }\n log(logSpace, '' + gg.length + ' selected groups. ')\n}\n\nasync function loadIndexHandler (loadIndexButton, logSpace) {\n loadIndexButton.classList.add('toolsButton--loading')\n loadIndexButton.classList.remove('toolsButton--error', 'toolsButton--success')\n const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))\n try {\n await kb.fetcher.load(nameEmailIndex)\n } catch (e) {\n loadIndexButton.classList.remove('toolsButton--loading')\n loadIndexButton.classList.add('toolsButton--error')\n log(logSpace, 'Error: People index has NOT been loaded' + e + '\\n')\n }\n loadIndexButton.classList.remove('toolsButton--loading')\n loadIndexButton.classList.add('toolsButton--success')\n log(logSpace, ' People index has been loaded\\n')\n} // loadIndexHandler\n\nasync function fixGroupless (book) {\n const groupless = await getGroupless(book)\n if (groupless.length === 0) {\n log(logSpace, 'No groupless contacts found.')\n return\n }\n let groupOfUngrouped = null\n try {\n groupOfUngrouped = await saveNewGroup(book, 'No group')\n } catch (_e) {\n // do nothing\n }\n\n const dom = logSpace.ownerDocument\n return new Promise(function (resolve) {\n const msg = dom.createElement('p')\n msg.textContent = `Add the ${groupless.length} contacts without groups to a 'No group' group?`\n logSpace.appendChild(msg)\n const confirmButton = UI.widgets.continueButton(dom, async function () {\n msg.remove()\n confirmButton.remove()\n for (const person of groupless) {\n if (groupOfUngrouped) {\n log(logSpace, ' adding ' + UI.utils.label(person))\n await addPersonToGroup(person, groupOfUngrouped)\n }\n }\n log(logSpace, 'People moved to group.')\n if (refreshGroupsFn) refreshGroupsFn()\n resolve()\n })\n logSpace.appendChild(confirmButton)\n })\n}\n\nasync function getGroupless (book) {\n const groupIndex = kb.any(book, ns.vcard('groupIndex'))\n const nameEmailIndex = kb.any(book, ns.vcard('nameEmailIndex'))\n try {\n await kb.fetcher.load([nameEmailIndex, groupIndex])\n const groups = kb.each(book, ns.vcard('includesGroup'))\n await kb.fetcher.load(groups)\n } catch (e) {\n debug.error('Error loading groups. Stack: ' + e)\n log(logSpace, 'Error loading groups or name index. If it persists, contact your admin.')\n }\n\n const reverseIndex = {}\n const groupless = []\n let groups = kb.each(book, VCARD('includesGroup'))\n const strings = new Set(groups.map(group => normalizeGroupUri(group.uri))) // remove dups with normalized URIs\n groups = [...strings].map(uri => kb.sym(uri))\n log(logSpace, '' + groups.length + ' total groups. ')\n\n for (let i = 0; i < groups.length; i++) {\n const g = groups[i]\n const a = groupMembers(kb, g)\n\n log(logSpace, UI.utils.label(g) + ': ' + a.length + ' members')\n for (let j = 0; j < a.length; j++) {\n kb.allAliases(a[j]).forEach(function (y) {\n reverseIndex[y.uri] = g\n })\n }\n }\n\n const cards = kb.each(undefined, VCARD('inAddressBook'), book)\n log(logSpace, '' + cards.length + ' total contatcs')\n for (let c = 0; c < cards.length; c++) {\n if (!reverseIndex[cards[c].uri]) {\n groupless.push(cards[c])\n log(logSpace, ' groupless ' + UI.utils.label(cards[c]))\n }\n }\n log(logSpace, '' + groupless.length + ' groupless contacts.')\n return groupless\n}\n\n/*\nasync function fixToOldDataModel (book) {\n async function updateToOldDataModel (groups) {\n let ds = []\n let ins = []\n groups.forEach(group => {\n let vcardOrWebids = kb.statementsMatching(null, ns.owl('sameAs'), null, group.doc()).map(st => st.subject)\n const strings = new Set(vcardOrWebids.map(contact => contact.uri)) // remove dups\n vcardOrWebids = [...strings].map(uri => kb.sym(uri))\n vcardOrWebids.forEach(item => {\n if (!kb.each(item, ns.vcard('fn'), null, group.doc()).length) {\n // delete item this is a new data model, item is a webid not a card.\n ds = ds.concat(kb\n .statementsMatching(item, ns.owl('sameAs'), null, group.doc())\n .concat(kb.statementsMatching(undefined, undefined, item, group.doc())))\n // add webid card to group\n const cards = kb.each(item, ns.owl('sameAs'), null, group.doc())\n cards.forEach(card => {\n ins = ins.concat($rdf.st(card, ns.owl('sameAs'), item, group.doc()))\n .concat($rdf.st(group, ns.vcard('hasMember'), card, group.doc()))\n })\n }\n })\n })\n if (ds.length) {\n const dom = logSpace.ownerDocument\n return new Promise(function (resolve) {\n const msg = dom.createElement('p')\n msg.textContent = 'Groups can be updated to old data model?'\n logSpace.appendChild(msg)\n const confirmButton = UI.widgets.continueButton(dom, async function () {\n msg.remove()\n confirmButton.remove()\n await kb.updater.updateMany(ds, ins)\n log(logSpace, 'Update done')\n resolve()\n })\n logSpace.appendChild(confirmButton)\n })\n } else {\n log(logSpace, 'Nothing to update.\\nAll groups already use the old data model.')\n }\n }\n let groups = kb.each(book, VCARD('includesGroup'))\n const strings = new Set(groups.map(group => normalizeGroupUri(group.uri))) // remove dups with normalized URIs\n groups = [...strings].map(uri => kb.sym(uri))\n updateToOldDataModel(groups)\n}\n */\n","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./utilities.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./utilities.css\";\n export default content && content.locals ? content.locals : undefined;\n","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!./contactsPane.css\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\noptions.insert = insertFn.bind(null, \"head\");\noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!./contactsPane.css\";\n export default content && content.locals ? content.locals : undefined;\n","/* Contact AddressBook Pane\n**\n** This outline pane allows a user to interact with a contact,\nto change its state according to an ontology, comment on it, etc.\n**\n** See also things like\n** http://www.w3.org/TR/vcard-rdf/\n** http://tools.ietf.org/html/rfc6350\n** http://www.iana.org/assignments/vcard-elements/vcard-elements.xhtml\n**\n*/\n\nimport { authn } from 'solid-logic'\nimport { saveNewContact, saveNewGroup } from './contactLogic'\nimport * as UI from 'solid-ui'\nimport { mintNewAddressBook } from './mintNewAddressBook'\nimport { renderIndividual } from './individual'\nimport { toolsPane } from './toolsPane'\nimport './styles/utilities.css'\nimport './styles/contactsPane.css'\nimport {\n checkDataModel, ensureBookLoaded, renderGroupButtons,\n refreshThingsSelected, refreshNames, selectAllGroups, loadAllGroups,\n syncGroupUl, setActiveGroupButton, createGroupLi, refreshFilteredPeople,\n deselectAllPeople, handleURIsDroppedOnGroup\n} from './addressBookPresenter'\nimport { alertDialog, complain, deleteThingAndDoc, setDom, setupResponsiveStacking } from './localUtils'\nimport * as debug from './debug'\nimport './styles/contactsRDFFormsEnforced.css'\n\nconst ns = UI.ns\nconst utils = UI.utils\n\nexport default {\n icon: UI.icons.iconBase + 'noun_99101.svg', // changed from embedded icon 2016-05-01\n\n name: 'contact',\n\n global: false,\n\n // Does the subject deserve a contact pane?\n label: function (subject, context) {\n const t = context.session.store.findTypeURIs(subject)\n // with the new design we only display Address Books\n // individuals are rendered through the profile-pane but not Organizations\n if (t[ns.vcard('Organization').uri]) return 'Contact'\n /*\n if (t[ns.vcard('Individual').uri]) return 'Contact'\n if (t[ns.foaf('Person').uri]) return 'Person'\n if (t[ns.schema('Person').uri]) return 'Person'\n if (t[ns.vcard('Group').uri]) return 'Group'\n */\n if (t[ns.vcard('AddressBook').uri]) return 'Address book'\n return null // No, under other circumstances\n },\n\n mintClass: UI.ns.vcard('AddressBook'),\n\n mintNew: mintNewAddressBook, // Make a new address book\n\n // Render the pane\n render: function (subject, dataBrowserContext, paneOptions = {}) {\n /*\n function newAddressBookButton (thisAddressBook) {\n return UI.login.newAppInstance(\n dom,\n { noun: 'address book', appPathSegment: 'contactorator.timbl.com' },\n function (ws, newBase) {\n thisPane.mintNew(thisAddressBook, newBase, {\n me,\n div,\n dom\n })\n }\n )\n } */\n\n const dom = dataBrowserContext.dom\n const kb = dataBrowserContext.session.store\n const div = dom.createElement('div')\n setDom(dom) // set dom for ana error handling in other modules\n\n UI.aclControl.preventBrowserDropEvents(dom) // protect drag and drop\n\n div.setAttribute('class', 'contactPane')\n // Make the pane stack vertically (sidebar -> details) when narrow\n // Set breakpoint to 1000 so it triggers at 980 width too.\n setupResponsiveStacking(div, 1000)\n\n asyncRender().then(\n () => debug.log('Contacts pane rendered for ' + subject),\n err => complain(div, dom, err.message || '' + err)\n ).catch(err => {\n complain(div, dom, err.message || '' + err)\n })\n return div\n\n // Async part of render. Maybe API will later allow render to be async\n async function asyncRender () {\n UI.aclControl.preventBrowserDropEvents(dom)\n\n const t = kb.findTypeURIs(subject)\n\n // Render a single contact Individual\n if (\n t[ns.vcard('Individual').uri] ||\n t[ns.foaf('Person').uri] ||\n t[ns.schema('Person').uri] ||\n t[ns.vcard('Organization').uri] ||\n t[ns.schema('Organization').uri]\n ) {\n try {\n await renderIndividual(dom, div, subject, dataBrowserContext)\n } catch (err) {\n debug.error('Error rendering contact. Stack: ' + err)\n throw new Error('Failed to render contact: ' + (err.message || err))\n }\n /*\n // Render a Group instance\n }\n else if (t[ns.vcard('Group').uri]) {\n // If we have a main address book, then render this group as a guest group within it\n UI.login\n .findAppInstances(context, ns.vcard('AddressBook'))\n .then(function (context) {\n const addressBooks = context.instances\n const options = { foreignGroup: subject }\n if (addressBooks.length > 0) {\n // const book = addressBooks[0]\n renderAddressBook(addressBooks, options)\n } else {\n renderAddressBook([], options)\n // @@ button to Make a new addressBook\n }\n })\n .catch(function (e) {\n complain(div, dom, '' + e)\n })\n */\n // Render a AddressBook instance\n } else if (t[ns.vcard('AddressBook').uri]) {\n renderAddressBook([subject], {})\n } else {\n debug.error('No evidence that ' + subject + ' is anything to do with contacts.')\n throw new Error('This does not seem to be a contact or address book.')\n }\n\n let me = authn.currentUser()\n\n // Render AddressBook instance\n function renderAddressBook (books, options) {\n kb.fetcher\n .load(books)\n .then(function (_xhr) {\n renderAddressBookDetails(books, options)\n })\n .catch(function (err) {\n debug.error('Error loading address book. Stack: ' + err)\n throw new Error('Failed to load address book.')\n })\n }\n\n function renderAddressBookDetails (books, options) {\n const classLabel = utils.label(ns.vcard('AddressBook'))\n\n let book = options.foreignGroup // in case we have only a Grouo\n let title = ''\n if (books && books.length > 0) {\n book = books[0] // if we have an Address Book, we prefer this\n title = utils.label(book.dir())\n } else {\n kb.any(book, ns.dc('title')) || kb.any(book, ns.vcard('fn'))\n if (paneOptions.solo && title && typeof document !== 'undefined') {\n document.title = title.value // @@ only when the outermmost pane\n }\n title = title ? title.value : classLabel\n }\n\n const groupIndex = kb.any(book, ns.vcard('groupIndex'))\n const selectedGroups = {}\n let selectedPeople = {} // Actually prob max 1\n\n let allGroupsLi = null\n let newGroupLi = null\n\n // Centralized active-button tracking across all action buttons\n const actionButtons = []\n function setActiveActionButton (activeBtn) {\n actionButtons.forEach(btn => {\n btn.classList.remove('btn-primary')\n btn.classList.add('btn-secondary')\n })\n if (activeBtn) {\n activeBtn.classList.remove('btn-secondary')\n activeBtn.classList.add('btn-primary')\n }\n }\n\n // Shared context passed to all builder functions\n const ctx = {\n dom,\n kb,\n ns,\n book,\n options,\n title,\n groupIndex,\n selectedGroups,\n get selectedPeople () { return selectedPeople },\n set selectedPeople (v) { selectedPeople = v },\n get allGroupsLi () { return allGroupsLi },\n set allGroupsLi (v) { allGroupsLi = v },\n get newGroupLi () { return newGroupLi },\n set newGroupLi (v) { newGroupLi = v },\n actionButtons,\n setActiveActionButton,\n dataBrowserContext,\n div,\n me,\n setMe (v) { me = v },\n paneOptions,\n }\n\n // ── Build layout ────────────────────────────────────────────\n const { main, addressBookSection, detailsSection } = buildMainLayout(ctx)\n div.appendChild(main)\n\n function showDetailsSection () {\n detailsSection.classList.remove('hidden')\n }\n ctx.showDetailsSection = showDetailsSection\n ctx.detailsSection = detailsSection\n\n // Create shared DOM elements needed by multiple builders\n const ulPeople = dom.createElement('ul')\n ulPeople.setAttribute('role', 'list')\n ulPeople.setAttribute('aria-label', 'People list')\n ctx.ulPeople = ulPeople\n // make the element available on the dataBrowserContext too; other\n // modules (individual/group membership) look for this property when\n // they need to refresh the master list after a mutation.\n if (ctx.dataBrowserContext) ctx.dataBrowserContext.ulPeople = ulPeople\n\n const detailsSectionContent = dom.createElement('div')\n detailsSectionContent.classList.add('detailsSectionContent')\n detailsSectionContent.setAttribute('role', 'region')\n detailsSectionContent.setAttribute('aria-labelledby', 'detailsSectionContent')\n detailsSectionContent.setAttribute('aria-live', 'polite')\n ctx.detailsSectionContent = detailsSectionContent\n\n // ── Header (title + New Contact button) ─────────────────────\n const headerSection = buildHeaderSection(ctx)\n addressBookSection.appendChild(headerSection)\n\n const dottedHr = dom.createElement('hr')\n dottedHr.classList.add('dottedHr')\n addressBookSection.appendChild(dottedHr)\n\n // ── Search ──────────────────────────────────────────────────\n const { searchSection, searchInput } = buildSearchSection(ctx)\n ctx.searchInput = searchInput\n addressBookSection.appendChild(searchSection)\n\n // ── Group bar ───────────────────────────────────────────────\n const { buttonSection, ulGroups } = buildGroupBar(ctx)\n ctx.ulGroups = ulGroups\n addressBookSection.appendChild(buttonSection)\n\n // ── People list ─────────────────────────────────────────────\n const peopleListSection = dom.createElement('section')\n peopleListSection.classList.add('peopleSection')\n addressBookSection.appendChild(peopleListSection)\n peopleListSection.appendChild(ulPeople)\n\n // ── Details content section ─────────────────────────────────\n detailsSection.appendChild(detailsSectionContent)\n\n // ── Footer buttons ──────────────────────────────────────────\n const cardFooter = buildFooterButtons(ctx)\n addressBookSection.appendChild(cardFooter)\n\n checkDataModel(book, detailsSectionContent).then(() => { debug.log('Async checkDataModel done.') })\n }\n\n // /////////////// Fix user when testing on a plane\n\n if (\n typeof document !== 'undefined' &&\n document.location &&\n ('' + document.location).slice(0, 16) === 'http://localhost'\n ) {\n const inferredOwner = kb.any(subject, UI.ns.acl('owner')) // when testing on plane with no webid\n if (inferredOwner) {\n me = inferredOwner\n }\n }\n\n return div\n } // asyncRender\n } // render function\n} // pane object\n\n// ── Helper: handle \"New group\" button click ──────────────────────────\nasync function handleNewGroupClick (ctx) {\n const { dom, kb, ns, book, options, selectedGroups, dataBrowserContext } = ctx\n ctx.showDetailsSection()\n ctx.detailsSectionContent.innerHTML = ''\n const groupIndex = kb.any(book, ns.vcard('groupIndex'))\n try {\n await kb.fetcher.load(groupIndex)\n } catch (e) {\n debug.log('Error: Group index NOT loaded:' + e + '\\n')\n }\n debug.log(' Group index has been loaded\\n')\n\n const name = await UI.widgets.askName(\n dom, kb, ctx.detailsSectionContent, UI.ns.foaf('name'), ns.vcard('Group'), 'group')\n if (!name) return // cancelled by user\n let group\n try {\n group = await saveNewGroup(book, name)\n } catch (err) {\n debug.log('Error: can\\'t save new group:' + err)\n ctx.detailsSectionContent.innerHTML = 'Failed to save group' + err\n return\n }\n for (const key in selectedGroups) delete selectedGroups[key]\n selectedGroups[group.uri] = true\n\n // Refresh the group buttons list\n const allGroupsLi = ctx.allGroupsLi\n const newGroupLi = ctx.newGroupLi\n if (allGroupsLi.parentNode) allGroupsLi.parentNode.removeChild(allGroupsLi)\n if (newGroupLi.parentNode) newGroupLi.parentNode.removeChild(newGroupLi)\n syncGroupUl(book, options, ctx.ulGroups, dom, selectedGroups, ctx.ulPeople, ctx.searchInput)\n ctx.ulGroups.insertBefore(allGroupsLi, ctx.ulGroups.firstChild)\n ctx.ulGroups.appendChild(newGroupLi)\n refreshThingsSelected(ctx.ulGroups, selectedGroups)\n // Highlight the new group button in ulGroups and show empty people list\n const matchingLi = Array.from(ctx.ulGroups.children).find(li => li.subject && li.subject.uri === group.uri)\n setActiveGroupButton(ctx.ulGroups, matchingLi ? matchingLi.querySelector('button') : null)\n refreshNames(ctx.ulPeople, null, false)\n\n ctx.detailsSectionContent.innerHTML = ''\n ctx.detailsSectionContent.appendChild(UI.aclControl.ACLControlBox5(\n group.doc(), dataBrowserContext, 'group', kb,\n function (ok, body) {\n if (!ok) {\n ctx.detailsSectionContent.innerHTML =\n 'Group sharing setup failed: ' + body\n }\n }))\n}\n\n// ── Helper: render askName form for person or organization ───────────\nfunction createNewPersonOrOrganization (ctx, formContainer, klass) {\n const { dom, kb, book, selectedGroups, dataBrowserContext } = ctx\n formContainer.innerHTML = ''\n UI.widgets\n .askName(dom, kb, formContainer, UI.ns.foaf('name'), klass)\n .then(async (name) => {\n if (!name) return // cancelled by user\n ctx.detailsSectionContent.innerHTML = 'Indexing...'\n let person\n try {\n person = await saveNewContact(book, name, selectedGroups, klass)\n } catch (err) {\n const msg = 'Error saving contact. If it persists, contact your admin.'\n alertDialog(msg)\n return\n }\n // It’s possible `saveNewContact` returned `undefined` when no group was\n // selected. In that case we already alerted the user and nothing more\n // should happen.\n if (!person) {\n ctx.detailsSectionContent.innerHTML = ''\n return\n }\n ctx.selectedPeople = {}\n ctx.selectedPeople[person.uri] = true\n refreshNames(ctx.ulPeople, null) // Add name to list of group\n ctx.detailsSectionContent.innerHTML = '' // Clear 'indexing'\n ctx.detailsSectionContent.classList.add('detailsSectionContent--wide')\n const contactPane = dataBrowserContext.session.paneRegistry.byName('contact')\n const paneDiv = contactPane.render(person, dataBrowserContext)\n paneDiv.classList.add('renderPane')\n ctx.detailsSectionContent.appendChild(paneDiv)\n })\n}\n\n// ── Builder: main layout skeleton ────────────────────────────────────\nfunction buildMainLayout (ctx) {\n const { dom } = ctx\n const main = dom.createElement('main')\n main.id = 'main-content'\n main.classList.add('addressBook-grid')\n main.setAttribute('role', 'main')\n main.setAttribute('aria-label', 'Address Book')\n main.setAttribute('tabindex', '-1')\n\n const addressBookSection = dom.createElement('section')\n addressBookSection.setAttribute('aria-labelledby', 'addressBook-section')\n addressBookSection.classList.add('addressBookSection', 'section-bg')\n addressBookSection.setAttribute('role', 'region')\n addressBookSection.setAttribute('tabindex', '-1')\n main.appendChild(addressBookSection)\n\n const detailsSection = dom.createElement('section')\n detailsSection.classList.add('detailSection')\n detailsSection.setAttribute('role', 'region')\n detailsSection.setAttribute('aria-label', 'Details section')\n detailsSection.classList.add('hidden')\n main.appendChild(detailsSection)\n\n return { main, addressBookSection, detailsSection }\n}\n\n// ── Builder: header with title and New Contact button ────────────────\nfunction buildHeaderSection (ctx) {\n const { dom, ns, title, me, setMe, setActiveActionButton } = ctx\n\n const headerSection = dom.createElement('section')\n headerSection.classList.add('headerSection')\n\n const header = dom.createElement('header')\n header.classList.add('mb-md')\n const h2 = dom.createElement('h2')\n h2.id = 'addressBook-heading'\n h2.setAttribute('tabindex', '-1')\n h2.textContent = title\n\n // New Contact button\n const newContactButton = dom.createElement('button')\n const container = dom.createElement('div')\n newContactButton.setAttribute('type', 'button')\n if (!me) newContactButton.setAttribute('disabled', 'true')\n authn.checkUser().then(webId => {\n if (webId) {\n setMe(webId)\n newContactButton.removeAttribute('disabled')\n }\n })\n container.appendChild(newContactButton)\n newContactButton.innerHTML = '+ New contact'\n newContactButton.classList.add('actionButton', 'btn-primary', 'action-button-focus')\n let newContactClickGeneration = 0\n newContactButton.addEventListener('click', async function (_event) {\n setActiveActionButton(null)\n deselectAllPeople(ctx.ulPeople)\n const thisGeneration = ++newContactClickGeneration\n ctx.showDetailsSection()\n ctx.detailsSectionContent.innerHTML = ''\n ctx.detailsSectionContent.classList.remove('detailsSectionContent--wide')\n await ensureBookLoaded()\n // Bail out if a newer click has taken over\n if (thisGeneration !== newContactClickGeneration) return\n ctx.detailsSectionContent.innerHTML = ''\n\n const chooserDiv = dom.createElement('div')\n chooserDiv.classList.add('contactTypeChooser')\n\n const selectLabel = dom.createElement('label')\n selectLabel.textContent = 'Contact type: '\n selectLabel.setAttribute('for', 'contactTypeSelect')\n chooserDiv.appendChild(selectLabel)\n\n const select = dom.createElement('select')\n select.id = 'contactTypeSelect'\n select.classList.add('contactTypeSelect')\n const optIndividual = dom.createElement('option')\n optIndividual.value = 'Individual'\n optIndividual.textContent = 'New person'\n select.appendChild(optIndividual)\n const optOrganization = dom.createElement('option')\n optOrganization.value = 'Organization'\n optOrganization.textContent = 'New organization'\n select.appendChild(optOrganization)\n chooserDiv.appendChild(select)\n\n ctx.detailsSectionContent.appendChild(chooserDiv)\n\n const remark = dom.createElement('p')\n remark.classList.add('contactCreationRemark')\n remark.textContent = 'The new contact is added to the already selected group.'\n ctx.detailsSectionContent.appendChild(remark)\n\n // Container for the askName form, placed below the select\n const formContainer = dom.createElement('div')\n formContainer.classList.add('contactFormContainer')\n ctx.detailsSectionContent.appendChild(formContainer)\n\n function currentKlass () {\n return select.value === 'Organization'\n ? ns.vcard('Organization')\n : ns.vcard('Individual')\n }\n\n // Render person form immediately as default\n createNewPersonOrOrganization(ctx, formContainer, currentKlass())\n\n // Switch form when dropdown changes\n select.addEventListener('change', function () {\n createNewPersonOrOrganization(ctx, formContainer, currentKlass())\n })\n }, false)\n\n // TODO we should also add if it is public or private\n header.appendChild(h2)\n header.appendChild(container)\n headerSection.appendChild(header)\n return headerSection\n}\n\n// ── Builder: search input section ────────────────────────────────────\nfunction buildSearchSection (ctx) {\n const { dom } = ctx\n const searchSection = dom.createElement('section')\n searchSection.classList.add('searchSection')\n const searchDiv = dom.createElement('div')\n searchDiv.classList.add('searchDiv')\n // container for input + clear button\n searchSection.appendChild(searchDiv)\n const searchInput = dom.createElement('input')\n searchInput.setAttribute('type', 'text')\n searchInput.setAttribute('aria-label', 'Search contacts')\n searchInput.classList.add('searchInput')\n searchInput.setAttribute('placeholder', 'Search by name in selected group')\n searchDiv.appendChild(searchInput)\n\n // clear button that appears when there is text\n const clearBtn = dom.createElement('button')\n clearBtn.setAttribute('type', 'button')\n clearBtn.setAttribute('aria-label', 'Clear search')\n clearBtn.classList.add('searchClearButton', 'hidden')\n clearBtn.textContent = '\\u2715' // multiplication sign ×\n searchDiv.appendChild(clearBtn)\n\n searchInput.addEventListener('input', function (_event) {\n const hasText = searchInput.value.length > 0\n // show/hide using the shared \"hidden\" utility class instead of direct\n // style manipulation\n clearBtn.classList.toggle('hidden', !hasText)\n refreshFilteredPeople(ctx.ulPeople, true, ctx.detailsSectionContent)\n })\n\n clearBtn.addEventListener('click', function () {\n searchInput.value = ''\n clearBtn.classList.add('hidden')\n searchInput.focus()\n refreshFilteredPeople(ctx.ulPeople, true, ctx.detailsSectionContent)\n })\n\n return { searchSection, searchInput }\n}\n\n// ── Builder: group buttons bar ───────────────────────────────────────\nfunction buildGroupBar (ctx) {\n const {\n dom, kb, book, options, groupIndex, selectedGroups,\n actionButtons, setActiveActionButton\n } = ctx\n\n const buttonSection = dom.createElement('section')\n buttonSection.classList.add('buttonSection')\n\n const ulGroups = dom.createElement('ul')\n ulGroups.classList.add('groupButtonsList')\n ulGroups.setAttribute('role', 'list')\n ulGroups.setAttribute('aria-label', 'Groups list')\n\n if (options.foreignGroup) {\n selectedGroups[options.foreignGroup.uri] = true\n }\n\n if (book) {\n // All groups button — leftmost, initially selected\n ctx.allGroupsLi = dom.createElement('li')\n const allGroupsButton = dom.createElement('button')\n allGroupsButton.textContent = 'All groups'\n allGroupsButton.classList.add('allGroupsButton', 'actionButton', 'btn-primary', 'action-button-focus', 'allGroupsButton--selected')\n allGroupsButton.addEventListener('click', function (_event) {\n setActiveGroupButton(ulGroups, allGroupsButton)\n setActiveActionButton(null)\n // Check if all groups are currently selected\n const allSelected = Array.from(ulGroups.children).every(function (li) {\n if (!li.subject) return true // skip non-group items (All groups, New group)\n return !!selectedGroups[li.subject.uri]\n })\n\n if (!allSelected) {\n allGroupsButton.classList.add('allGroupsButton--loading')\n allGroupsButton.setAttribute('aria-busy', 'true')\n selectAllGroups(selectedGroups, ulGroups, function (ok, message) {\n if (!ok) return alertDialog('Failed to select all groups. If it persists, contact admin.')\n allGroupsButton.classList.remove('allGroupsButton--loading')\n allGroupsButton.setAttribute('aria-busy', 'false')\n allGroupsButton.classList.add('allGroupsButton--active')\n refreshThingsSelected(ulGroups, selectedGroups)\n refreshNames(ctx.ulPeople, null)\n })\n } else {\n allGroupsButton.classList.remove('allGroupsButton--loading', 'allGroupsButton--active')\n allGroupsButton.setAttribute('aria-busy', 'false')\n allGroupsButton.classList.add('allGroupsButton--loaded') // pale green hint groups loaded\n for (const key in selectedGroups) delete selectedGroups[key]\n refreshThingsSelected(ulGroups, selectedGroups)\n }\n }) // on button click\n ctx.allGroupsLi.appendChild(allGroupsButton)\n ulGroups.appendChild(ctx.allGroupsLi) // First item in the list\n\n // New group button — rightmost (appended after group buttons are rendered)\n ctx.newGroupLi = dom.createElement('li')\n const newGroupButton = dom.createElement('button')\n newGroupButton.setAttribute('type', 'button')\n newGroupButton.innerHTML = '+ New group'\n newGroupButton.classList.add('allGroupsButton', 'actionButton', 'btn-secondary', 'action-button-focus')\n actionButtons.push(newGroupButton)\n newGroupButton.addEventListener(\n 'click', function (event) {\n setActiveGroupButton(ulGroups, newGroupButton)\n setActiveActionButton(null)\n deselectAllPeople(ctx.ulPeople)\n handleNewGroupClick(ctx)\n },\n false\n )\n ctx.newGroupLi.appendChild(newGroupButton)\n\n // Append ulGroups to buttonSection, then add New group at the end\n buttonSection.appendChild(ulGroups)\n\n if (groupIndex) {\n kb.fetcher.nowOrWhenFetched(groupIndex.uri, book, function (ok, body) {\n if (!ok) {\n debug.error('Error loading group index. Stack: ' + body)\n alertDialog('Error loading group index. If it persists, contact admin.')\n return\n }\n // Remove special items before sync (syncTableToArrayReOrdered expects .subject on all children)\n if (ctx.allGroupsLi.parentNode) ctx.allGroupsLi.parentNode.removeChild(ctx.allGroupsLi)\n if (ctx.newGroupLi.parentNode) ctx.newGroupLi.parentNode.removeChild(ctx.newGroupLi)\n syncGroupUl(book, options, ulGroups, dom, selectedGroups, ctx.ulPeople, ctx.searchInput) // Refresh list of groups\n ulGroups.insertBefore(ctx.allGroupsLi, ulGroups.firstChild) // Keep All contacts first\n ulGroups.appendChild(ctx.newGroupLi) // Keep New group last\n\n // Auto-select all groups and display all contacts on load\n allGroupsButton.classList.add('allGroupsButton--loading')\n allGroupsButton.setAttribute('aria-busy', 'true')\n selectAllGroups(selectedGroups, ulGroups, function (ok, message) {\n if (!ok) return alertDialog('Failed to select all groups. If it persists, contact admin.')\n allGroupsButton.classList.remove('allGroupsButton--loading')\n allGroupsButton.setAttribute('aria-busy', 'false')\n allGroupsButton.classList.add('allGroupsButton--active')\n refreshThingsSelected(ulGroups, selectedGroups)\n refreshNames(ctx.ulPeople, null)\n })\n })\n }\n\n // Remove special items before initial render too\n if (ctx.allGroupsLi.parentNode) ctx.allGroupsLi.parentNode.removeChild(ctx.allGroupsLi)\n if (ctx.newGroupLi.parentNode) ctx.newGroupLi.parentNode.removeChild(ctx.newGroupLi)\n renderGroupButtons(book, ulGroups, options, dom, selectedGroups, ctx.ulPeople, ctx.searchInput, ctx.detailsSectionContent, ctx.dataBrowserContext, function () {\n setActiveActionButton(null)\n // Keep the details section open when a contact or New contact form is showing\n if (!ctx.detailsSectionContent.querySelector('.contactTypeChooser, .contactFormContainer, .renderPane')) {\n ctx.detailsSectionContent.innerHTML = ''\n ctx.detailsSection.classList.add('hidden')\n }\n })\n ulGroups.insertBefore(ctx.allGroupsLi, ulGroups.firstChild) // Keep All contacts first\n ulGroups.appendChild(ctx.newGroupLi) // Ensure New group is last after initial render\n } else {\n syncGroupUl(book, options, ulGroups, dom, selectedGroups, ctx.ulPeople, ctx.searchInput) // Refresh list of groups (will be empty)\n refreshNames(ctx.ulPeople, null)\n debug.log('No book, only one group -> hide list of groups')\n } // if not book\n\n return { buttonSection, ulGroups }\n}\n\n// ── Builder: footer action buttons (Groups / Sharing / Tools) ────────\nfunction buildFooterButtons (ctx) {\n const {\n dom, kb, ns, book, options, selectedGroups,\n actionButtons, setActiveActionButton, dataBrowserContext, div, me\n } = ctx\n\n const cardFooter = dom.createElement('div')\n cardFooter.classList.add('cardFooter')\n\n if (book) {\n // Groups button\n const groupsButton = cardFooter.appendChild(dom.createElement('button'))\n groupsButton.setAttribute('type', 'button')\n groupsButton.innerHTML = 'Groups'\n groupsButton.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n actionButtons.push(groupsButton)\n groupsButton.addEventListener('click', async function (_event) {\n setActiveActionButton(groupsButton)\n deselectAllPeople(ctx.ulPeople)\n ctx.showDetailsSection()\n ctx.detailsSectionContent.innerHTML = ''\n ctx.detailsSectionContent.classList.remove('detailsSectionContent--wide')\n\n // Header\n const groupsHeader = dom.createElement('h3')\n groupsHeader.textContent = 'Your groups'\n ctx.detailsSectionContent.appendChild(groupsHeader)\n\n let groupRemark = dom.createElement('p')\n groupRemark.textContent = 'When you delete a group it can happen that some contacts end up groupless.'\n ctx.detailsSectionContent.appendChild(groupRemark)\n\n groupRemark = dom.createElement('p')\n groupRemark.textContent = 'To move contacts around, simply drag and drop them onto a group.'\n ctx.detailsSectionContent.appendChild(groupRemark)\n\n // Load all groups and display them in a list\n let groups\n try {\n groups = await loadAllGroups(book)\n } catch (err) {\n ctx.detailsSectionContent.appendChild(dom.createTextNode('Failed to load groups: ' + err))\n return\n }\n\n const groupsList = dom.createElement('ul')\n groupsList.setAttribute('role', 'list')\n groupsList.setAttribute('aria-label', 'All groups')\n groupsList.classList.add('groupButtonsList')\n\n // Sort groups by name\n if (groups) {\n groups.sort((a, b) => {\n const nameA = (kb.any(a, ns.vcard('fn')) || '').toString().toLowerCase()\n const nameB = (kb.any(b, ns.vcard('fn')) || '').toString().toLowerCase()\n return nameA < nameB ? -1 : nameA > nameB ? 1 : 0\n })\n groups.forEach(function (group) {\n const { groupLi, groupButton: groupBtn, name } = createGroupLi(group)\n groupBtn.addEventListener('click', function (event) {\n event.preventDefault()\n if (!event.metaKey) {\n for (const key in selectedGroups) delete selectedGroups[key]\n }\n selectedGroups[group.uri] = !selectedGroups[group.uri]\n refreshThingsSelected(ctx.ulGroups, selectedGroups)\n // Highlight the matching group button in the sidebar ulGroups\n const matchingLi = Array.from(ctx.ulGroups.children).find(li => li.subject && li.subject.uri === group.uri)\n setActiveGroupButton(ctx.ulGroups, matchingLi ? matchingLi.querySelector('button') : null)\n kb.fetcher.nowOrWhenFetched(group.doc(), undefined, function (ok, message) {\n if (!ok) {\n debug.error('Cannot load group: ' + group + '. Stack: ' + message)\n return alertDialog('Failed to load group details. If it persists, contact your admin.')\n }\n refreshNames(ctx.ulPeople, null, false)\n })\n }, false)\n UI.widgets.makeDropTarget(groupLi, uris => handleURIsDroppedOnGroup(uris, group))\n\n if (me) {\n UI.widgets.deleteButtonWithCheck(\n dom,\n groupLi,\n 'group ' + name,\n async function () {\n await deleteThingAndDoc(group)\n delete selectedGroups[group.uri]\n // Refresh the group buttons list\n const allGroupsLi = ctx.allGroupsLi\n const newGroupLi = ctx.newGroupLi\n if (allGroupsLi.parentNode) allGroupsLi.parentNode.removeChild(allGroupsLi)\n if (newGroupLi.parentNode) newGroupLi.parentNode.removeChild(newGroupLi)\n syncGroupUl(book, options, ctx.ulGroups, dom, selectedGroups, ctx.ulPeople, ctx.searchInput)\n ctx.ulGroups.insertBefore(allGroupsLi, ctx.ulGroups.firstChild)\n ctx.ulGroups.appendChild(newGroupLi)\n refreshThingsSelected(ctx.ulGroups, selectedGroups)\n // Refresh the people list to reflect the deleted group\n refreshNames(ctx.ulPeople, null, false)\n // Refresh the groups detail view\n groupsButton.click()\n }\n )\n }\n\n groupsList.appendChild(groupLi)\n })\n }\n\n ctx.detailsSectionContent.appendChild(groupsList)\n\n // New group button at the bottom\n const newGroupBtn = dom.createElement('button')\n newGroupBtn.setAttribute('type', 'button')\n newGroupBtn.innerHTML = '+ New group'\n newGroupBtn.classList.add('actionButton', 'btn-primary', 'action-button-focus', 'newGroupBtn')\n newGroupBtn.addEventListener('click', function () { handleNewGroupClick(ctx) }, false)\n ctx.detailsSectionContent.appendChild(newGroupBtn)\n })\n\n // Sharing button\n const sharingButton = cardFooter.appendChild(dom.createElement('button'))\n sharingButton.setAttribute('type', 'button')\n sharingButton.innerHTML = 'Sharing'\n sharingButton.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n actionButtons.push(sharingButton)\n sharingButton.addEventListener('click', function (_event) {\n setActiveActionButton(sharingButton)\n deselectAllPeople(ctx.ulPeople)\n ctx.showDetailsSection()\n ctx.detailsSectionContent.innerHTML = ''\n ctx.detailsSectionContent.classList.remove('detailsSectionContent--wide')\n\n const sharingHeader = dom.createElement('h3')\n sharingHeader.textContent = 'Sharing'\n ctx.detailsSectionContent.appendChild(sharingHeader)\n\n ctx.detailsSectionContent.appendChild(\n UI.aclControl.ACLControlBox5(\n book.dir(),\n dataBrowserContext,\n 'book',\n kb,\n function (ok, body) {\n if (!ok) {\n debug.error('ACL control box Failed. Stack: ' + body)\n complain(ctx.detailsSectionContent, dom, 'Problem displaying sharing controls. If persists, contact admin.')\n }\n }\n )\n )\n\n const sharingContext = {\n target: book,\n me,\n noun: 'address book',\n div: ctx.detailsSectionContent,\n dom,\n statusRegion: div\n }\n UI.login.registrationControl(sharingContext, book, ns.vcard('AddressBook'))\n .then(() => debug.log('Registration control finished.'))\n .catch(e => {\n debug.error('Error in registration control. Stack: ' + e)\n complain(ctx.detailsSectionContent, dom, 'Problem displaying findable controls. If persists, contact admin.')\n })\n })\n\n // Settings button\n const toolsButton = cardFooter.appendChild(dom.createElement('button'))\n toolsButton.setAttribute('type', 'button')\n toolsButton.innerHTML = 'Tools'\n toolsButton.classList.add('actionButton', 'btn-secondary', 'action-button-focus')\n actionButtons.push(toolsButton)\n toolsButton.addEventListener('click', function (_event) {\n setActiveActionButton(toolsButton)\n deselectAllPeople(ctx.ulPeople)\n ctx.showDetailsSection()\n ctx.detailsSectionContent.innerHTML = ''\n ctx.detailsSectionContent.classList.add('detailsSectionContent--wide')\n ctx.detailsSectionContent.appendChild(\n toolsPane(\n selectAllGroups,\n selectedGroups,\n ctx.ulGroups,\n book,\n dataBrowserContext,\n me,\n function refreshGroups () {\n if (ctx.allGroupsLi.parentNode) ctx.allGroupsLi.parentNode.removeChild(ctx.allGroupsLi)\n if (ctx.newGroupLi.parentNode) ctx.newGroupLi.parentNode.removeChild(ctx.newGroupLi)\n syncGroupUl(book, options, ctx.ulGroups, dom, selectedGroups, ctx.ulPeople, ctx.searchInput)\n ctx.ulGroups.insertBefore(ctx.allGroupsLi, ctx.ulGroups.firstChild)\n ctx.ulGroups.appendChild(ctx.newGroupLi)\n refreshThingsSelected(ctx.ulGroups, selectedGroups)\n }\n )\n )\n })\n } // if book\n\n return cardFooter\n}\n\nexport { saveNewGroup, addPersonToGroup, groupMembers, saveNewContact } from './contactLogic'\nexport { addWebIDToContacts, removeWebIDFromContacts, getPersonas } from './webidControl'\n"],"names":[],"sourceRoot":""}