@import url("chrome://global/skin/tor-colors.css");

#category-connection > .category-icon {
  list-style-image: url("chrome://global/content/torconnect/tor-connect.svg");
}

/* Make a button appear disabled, whilst still allowing it to keep keyboard
 * focus.
 * TODO: Replace with moz-button when it handles this for us. See
 * tor-browser#43275. */
button.spoof-button-disabled {
  /* Borrow the :disabled rule from common-shared.css */
  opacity: 0.4;
  /* Also ensure it does not get hover or active styling. */
  pointer-events: none;
}

.tor-loading-icon {
  width: 16px;
  height: 16px;
  -moz-context-properties: fill;
  /* Use --tor-text-color. This will have good contrast for this small icon
   * against the background. And it will match the surrounding text for high
   * contrast and forced colour themes. */
  fill: var(--tor-text-color);
  content: url("chrome://global/skin/icons/loading.svg");
}

.tor-toggle {
  margin-block: 16px;
  width: max-content;
}

/* Status */

#network-status-internet-area {
  margin-block: 16px;
}

#network-status-tor-area {
  margin-block: 0 32px;
}

.network-status-area {
  display: flex;
  align-items: center;
  white-space: nowrap;
}

.network-status-area > * {
  flex: 0 0 auto;
}

.network-status-icon {
  width: 18px;
  height: 18px;
  margin-inline-end: 8px;
  -moz-context-properties: fill, stroke;
  fill: var(--icon-color);
  stroke: var(--icon-color);
}

#network-status-internet-area .network-status-icon {
  content: url("chrome://browser/content/torpreferences/network.svg");
}

#network-status-internet-area.status-offline .network-status-icon {
  content: url("chrome://browser/content/torpreferences/network-broken.svg");
}

#network-status-tor-area .network-status-icon {
  content: url("chrome://global/content/torconnect/tor-connect.svg");
}

#network-status-tor-area:not(.status-connected) .network-status-icon {
  content: url("chrome://global/content/torconnect/tor-connect-broken.svg");
}

#network-status-tor-area.status-blocked .network-status-icon {
  /* Same as .tor-connect-status-potentially-blocked. */
  stroke: var(--icon-color-critical);
}

.network-status-label {
  font-weight: var(--font-weight-bold);
  margin-inline-end: 0.75em;
}

.network-status-result {
  margin-inline-end: 0.75em;
}

#network-status-tor-area.status-connected #network-status-tor-connect-button {
  /* Hide button when already connected. */
  display: none;
}

/* Bridge settings */

.tor-medium-heading {
  /* Same font size as mozilla preferences h2. */
  font-size: var(--font-size-large);
  font-weight: var(--font-weight-bold);
  margin: 0;
}

.tor-small-heading {
  font-size: inherit;
  font-weight: var(--font-weight-bold);
  margin: 0;
}

/* Hide the tor-search-heading elements when the group's search header is
 * hidden. These only appear in search results.
 * See tor-browser#43320.
 * NOTE: `.search-header[hidden] ~ :is(* .tor-search-heading)` will not match
 * (possibly because the `~` selector is unsure how to integrate with the
 * non-compound `* .tor-search-heading` selector). So we need to duplicate the
 * `.search-header[hidden]` rule. */
#torPreferences-bridges-group :is(.search-header[hidden] ~ * .tor-search-heading, .search-header[hidden] ~ .tor-search-heading) {
  display: none;
}

/* Hide the tor-non-search-heading elements when the group's search header is
 * not hidden. These only appear outside of search results.
 * See tor-browser#43320. */
#torPreferences-bridges-group :is(.search-header:not([hidden]) ~ * .tor-non-search-heading, .search-header:not([hidden]) ~ .tor-non-search-heading) {
  display: none;
}

.tor-focusable-heading {
  /* Do not occupy more horizontal space than necessary. */
  width: fit-content;
}

.tor-focusable-heading:focus-visible {
  outline-offset: var(--focus-outline-offset);
}

.bridge-status-badge {
  display: flex;
  min-width: max-content;
  align-items: center;
  gap: 0.5em;
  font-size: var(--font-size-small);
}

.bridge-status-badge:not(.bridge-status-connected, .bridge-status-none, .bridge-status-current-built-in) {
  display: none;
}

@media not ((forced-colors) or (prefers-contrast)) {
  /* Accent colors are usually only used for background colors. Here we are
   * using it for text colors, so we only enable these rules when not using a
   * high contrast theme or forced colors. */
  .bridge-status-badge.bridge-status-connected {
    color: var(--tor-text-color);
  }

  .bridge-status-badge.bridge-status-current-built-in {
    color: var(--color-accent-primary);
  }
}

.bridge-status-badge > * {
  flex: 0 0 auto;
}

.bridge-status-icon {
  width: 16px;
  height: 16px;
  background-repeat: no-repeat;
  background-position: center center;
  -moz-context-properties: fill;
  fill: currentColor;
}

.bridge-status-badge:is(.bridge-status-connected, .bridge-status-current-built-in) .bridge-status-icon {
  background-image: url("chrome://global/skin/icons/check.svg");
}

.bridge-status-badge.bridge-status-none .bridge-status-icon {
  /* Hide the icon. */
  display: none;
}

#tor-bridges-update-area {
  /* Still accessible to screen reader, but not visual. */
  position: absolute;
  clip-path: inset(50%);
}

#torPreferences-bridges-group:not(.bridges-initialized) {
  /* Hide bridge settings whilst not initialized. */
  display: none;
}

#tor-bridges-none,
#tor-bridges-current {
  margin-inline: 0;
  margin-block: 32px;
}

#tor-bridges-none:not([hidden]) {
  display: grid;
  justify-items: center;
  text-align: center;
  padding-block: 64px;
  padding-inline: 32px;
  gap: 16px;
  border-radius: var(--border-radius-small);
  color: var(--text-color-deemphasized);
  border: 2px dashed var(--border-color-deemphasized);
}

#tor-bridges-none-icon {
  width: 20px;
  height: 20px;
  content: url("chrome://browser/content/torpreferences/bridge.svg");
  -moz-context-properties: fill;
  fill: currentColor;
}

.tor-bridges-box,
.tor-bridges-details-box {
  padding: 16px;
  border-radius: var(--border-radius-small);
  background: var(--background-color-box-info);
  border: 1px solid var(--border-color);
}

@media not forced-colors {
  .tor-bridges-box {
    border-color: transparent;
  }
}

#tor-bridges-current-header-bar {
  display: grid;
  min-width: max-content;
  grid-template: "heading source button" min-content / max-content 1fr max-content;
  align-items: center;
  border-block-end: 1px solid var(--border-color);
  padding-block-end: 16px;
  margin-block-end: 16px;
  white-space: nowrap;
}

.tor-bridges-current-heading {
  grid-area: heading;
}

.tor-bridges-source-label {
  margin-inline-start: 2em;
  margin-inline-end: 8px;
  grid-area: source;
  justify-self: end;
}

#tor-bridges-all-options-button {
  grid-area: button;
}

#tor-bridges-lox-label:not([hidden]) {
  display: flex;
  align-items: center;
  gap: 6px;
}

#tor-bridges-lox-label > * {
  flex: 0 0 auto;
}

#tor-bridges-lox-label-icon {
  content: url("chrome://browser/content/torpreferences/lox-bridge-pass.svg");
  width: 16px;
  height: 16px;
  -moz-context-properties: fill;
  fill: var(--icon-color);
}

.tor-bridges-options-button {
  padding: 3px;
  margin: 0;
  min-height: auto;
  min-width: auto;
  box-sizing: content-box;
  width: 16px;
  height: 16px;
  background-image: url("chrome://global/skin/icons/more.svg");
  background-repeat: no-repeat;
  background-position: center center;
  background-origin: content-box;
  background-size: contain;
  -moz-context-properties: fill;
  fill: currentColor;
}

#tor-bridges-built-in-display:not([hidden]) {
  display: grid;
  grid-template:
    "type status" min-content
    "description description" auto
    / max-content 1fr;
  gap: 12px 1.5em;
  margin-block-end: 16px;
}

#tor-bridges-built-in-type-name {
  font-weight: var(--font-weight-bold);
  grid-area: type;
}

#tor-bridges-built-in-connected {
  grid-area: status;
  justify-self: end;
}

#tor-bridges-built-in-description {
  grid-area: description;
}

.tor-bridges-grid:not([hidden]) {
  display: grid;
  grid-template-columns: max-content repeat(4, max-content) 1fr;
  --tor-bridges-grid-column-gap: 8px;
  --tor-bridges-grid-column-short-gap: 4px;
  /* For #tor-bridges-grid-display we want each grid item to have the same
   * height so that their focus outlines match. */
  align-items: stretch;
}

.tor-bridges-grid-row {
  /* We want each row to act as a row of three items in the
   * .tor-bridges-grid grid layout.
   * We also want a 16px spacing between rows, and 8px spacing between columns,
   * which are outside the .tor-bridges-grid-cell's border area.
   *
   * For #tor-bridges-grid-display this should ensure that clicking these gaps
   * will not focus any item, and their focus outlines do not overlap.
   * Moreover, we also want each row to show its .tor-bridges-options-cell when
   * the .tor-bridges-grid-row has :hover.
   *
   * We could use "display: contents" on the row and set a "gap: 16px 8px" on
   * the parent so that its items fall into the parent layout. However, the gap
   * between the items would mean there are places where no row has :hover. So
   * if the user glided across the grid, the options button would visibly
   * disappear any time the pointer entered a gap, causing the display to feel
   * "jumpy".
   *
   * Instead, we use a "subgrid" layout for each .tor-bridges-grid-row, and
   * using padding, rather than a gap, for the vertical spacing. Therefore,
   * every part of the grid is covered by a row, so moving the pointer over the
   * grid will always have one row with :hover, so one of the options cell will
   * always be visible.
   */
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  /* Add 16px gap between rows, plus 8px at the start and end of the grid. */
  padding-block: 8px;
}

#tor-bridges-grid-display .tor-bridges-grid-cell:focus-visible {
  /* #tor-bridges-grid-display has focus management for its cells. */
  outline: var(--focus-outline);
  outline-offset: var(--focus-outline-offset);
}

.tor-bridges-grid-cell {
  /* The cell is stretched to the height of the row, so that each focus outline
   * shares the same height, but we want to center-align the content within,
   * which is either a single Element or a TextNode. */
  display: grid;
  align-content: center;
}

.tor-bridges-type-cell {
  margin-inline-end: var(--tor-bridges-grid-column-gap);
}

.tor-bridges-emojis-block {
  /* Emoji block occupies four columns, but with a smaller gap. */
  display: contents;
}

.tor-bridges-emoji-cell:not(:last-child) {
  margin-inline-end: var(--tor-bridges-grid-column-short-gap);
}

.tor-bridges-emoji-icon {
  display: block;
  box-sizing: content-box;
  width: 16px;
  height: 16px;
  /* color-light-gray-10, color-dark-gray-60 */
  background: light-dark(#f9f9fb, #2b2a33);
  border-radius: var(--border-radius-small);
  padding: 8px;
}

.tor-bridges-grid-end-block {
  /* The last three cells all share a single grid item slot in the
   * #tor-bridges-grid-display layout.
   * This is because we do not want to align its cells between rows. */
  min-width: max-content;
  display: flex;
  /* Choose "stretch" instead of "center" so that focus outline is a consistent
   * height between cells. */
  align-items: stretch;
  margin-inline-start: var(--tor-bridges-grid-column-gap);
  gap: var(--tor-bridges-grid-column-gap);
}

.tor-bridges-address-cell {
  /* base size */
  width: 10em;
  flex: 1 0 auto;
}

.tor-bridges-address-cell-text {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text-color-deemphasized);
}

.tor-bridges-status-cell,
.tor-bridges-options-cell {
  flex: 0 0 auto;
}

/* Hide the options button if the row does not have hover or focus. */
.tor-bridges-grid-row:not(
  :hover,
  :focus-within
) .tor-bridges-options-cell,
/* Hide the status cell when it shows "No status" if the cell does not have
 * focus. */
.tor-bridges-grid-row.hide-status .tor-bridges-status-cell:not(:focus) {
  /* Still accessible to screen reader, but not visual and does not contribute
   * to the parent flex layout. */
  /* NOTE: We assume that the height of these cell's content is equal to or less
   * than the other cells, so there won't be a jump in row height when they
   * become visual again and contribute to the layout. */
  position: absolute;
  clip-path: inset(50%);
}

.tor-bridges-details-box {
  margin-block-start: 24px;
}

#tor-bridges-share:not([hidden]) {
  display: grid;
  grid-template:
    "heading heading heading" min-content
    /* If the description spans one line, it will be center-aligned with the
     * buttons, otherwise it will start to expand upwards. */
    "description . ." 1fr
    "description copy qr" min-content
    / 1fr max-content max-content;
  gap: 0 8px;
  align-items: center;
}

.tor-bridges-share-heading {
  grid-area: heading;
  margin-block-end: 4px;
}

#tor-bridges-share-description {
  grid-area: description;
}

#tor-bridges-copy-addresses-button {
  grid-area: copy;
  margin: 0;
  /* Match the QR height if it is higher than ours. */
  min-height: auto;
  align-self: stretch;
}

#tor-bridges-qr-addresses-button {
  grid-area: qr;
  padding: 5px;
  margin: 0;
  min-height: auto;
  min-width: auto;
  box-sizing: content-box;
  width: 24px;
  height: 24px;
  background-image: url("chrome://browser/content/torpreferences/bridge-qr.svg");
  background-repeat: no-repeat;
  background-position: center center;
  background-origin: content-box;
  background-size: contain;
  -moz-context-properties: fill;
  fill: currentColor;
}

#tor-bridges-lox-status {
  margin-block-start: 8px;
}

.tor-bridges-lox-box:not([hidden]) {
  display: grid;
  grid-template:
    "image intro intro" min-content
    ". list list" auto
    ". invites button" min-content
    / min-content 1fr max-content;
  align-items: start;
  gap: 8px;
}

.tor-bridges-lox-image-outer {
  grid-area: image;
  /* The ring is 36px by 36px, but has 4px of padding for a Gaussian blur. */
  width: 44px;
  height: 44px;
  margin: -4px;
  align-self: center;
  justify-self: center;
  /* fill is the progress, stroke is the empty ring. */
  -moz-context-properties: fill, stroke;
  fill: var(--icon-color-success);
  stroke: var(--border-color);
  content: url("chrome://browser/content/torpreferences/lox-progress-ring.svg");
}

#tor-bridges-lox-unlock-alert.lox-unlock-upgrade .tor-bridges-lox-image-outer {
  content: url("chrome://browser/content/torpreferences/lox-complete-ring.svg");
}

.tor-bridges-lox-image-inner {
  grid-area: image;
  /* Extra 4px space for gaussian blur. */
  width: 16px;
  height: 16px;
  align-self: center;
  justify-self: center;
  -moz-context-properties: fill;
  fill: var(--icon-color);
}

#tor-bridges-lox-details .tor-bridges-lox-image-inner {
  content: url("chrome://browser/content/torpreferences/lox-bridge-pass.svg");
}

#tor-bridges-lox-unlock-alert .tor-bridges-lox-image-inner {
  content: url("chrome://browser/content/torpreferences/bridge.svg");
}

#tor-bridges-lox-unlock-alert.lox-unlock-upgrade .tor-bridges-lox-image-inner {
  content: url("chrome://browser/content/torpreferences/lox-success.svg");
}

.tor-bridges-lox-intro {
  grid-area: intro;
  align-self: center;
  justify-self: start;
}

.tor-bridges-lox-list {
  grid-area: list;
  margin: 0;
  padding: 0;
  display: grid;
  /* Align the icons, as if list markers. */
  grid-template-columns: max-content 1fr;
  align-items: start;
  gap: 8px 0;
}

.tor-bridges-lox-list-item:not([hidden]) {
  display: contents;
}

.tor-bridges-lox-list-item:not([hidden])::before {
  /* We use ::before rather than list-style-image to have more control. */
  box-sizing: content-box;
  width: 18px;
  height: 18px;
  margin-inline: 4px 6px;
  /* We want the icons to be center-aligned relative to the *first* line. */
  margin-block-start: calc((1lh - 18px) / 2);
  /* We use display: grid rather than display: block. Otherwise the content will
   * be offset vertically by the line-height. */
  display: grid;
  /* fill is the icon color, stroke is the border color. */
  -moz-context-properties: fill, stroke;
  fill: var(--icon-color);
}

.tor-bridges-lox-list-item-bridge::before {
  content: url("chrome://browser/content/torpreferences/lox-bridge-icon.svg");
}

.tor-bridges-lox-list-item-invite::before {
  content: url("chrome://browser/content/torpreferences/lox-invite-icon.svg");
}

#tor-bridges-lox-details .tor-bridges-lox-list-item::before {
  stroke: var(--border-color);
}

#tor-bridges-lox-unlock-alert .tor-bridges-lox-list-item::before {
  stroke: var(--icon-color-success);
}

#tor-bridges-lox-remaining-invites {
  grid-area: invites;
  justify-self: end;
  align-self: center;
}

.tor-bridges-lox-button {
  grid-area: button;
  margin: 0;
  align-self: center;
}

.tor-bridges-provider-heading {
  margin-block: 48px 8px;
}

#tor-bridges-provider-area {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  align-items: start;
  margin-block-start: 24px;
}

#tor-bridges-provider-list {
  display: grid;
  grid-template-columns: max-content max-content;
  /* 24px gap between items. */
  gap: 24px 12px;
  margin-block: 16px;
  padding: 0;
}

.tor-bridges-provider-item {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
  align-items: center;
  justify-items: start;
  /* 8px gap between the name and instruction. */
  gap: 8px 12px;
}

.tor-bridges-provider-icon {
  width: 16px;
  height: 16px;
  -moz-context-properties: fill;
  fill: var(--icon-color);
}

#tor-bridges-provider-icon-telegram {
  content: url("chrome://browser/content/torpreferences/telegram-logo.svg");
}

#tor-bridges-provider-icon-web {
  content: url("chrome://browser/content/torpreferences/network.svg");
}

#tor-bridges-provider-icon-email {
  content: url("chrome://browser/content/torpreferences/mail.svg");
}

.tor-bridges-provider-name {
  font-weight: var(--font-weight-bold);
  font-size: var(--font-size-small);
}

.tor-bridges-provider-instruction {
  grid-column: 2 / 3;
}

#tor-bridges-request-box {
  /* Take up the full height in the container. */
  align-self: stretch;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  justify-content: center;
}

#tor-bridges-request-box > * {
  flex: 0 0 auto;
}

#tor-bridges-request-description {
  margin-block: 12px 16px;
}

#tor-bridges-open-request-dialog-button {
  margin: 0;
}

#torPreferences-bridges-location {
  width: 280px;
}

#torPreferences-bridges-location menuitem[disabled="true"] {
  color: var(--button-text-color, inherit);
  font-weight: var(--font-weight-bold);
}

/* Request bridges */

image#torPreferences-requestBridge-captchaImage {
  margin: 16px 0 8px 0;
  min-height: 140px;
}

button#torPreferences-requestBridge-refreshCaptchaButton {
  min-width: initial;
}

#torPreferences-requestBridge-refreshCaptchaButton image {
  -moz-context-properties: fill;
  fill: currentColor;
}

#torPreferences-requestBridge-captchaTextbox {
  flex: 1 0 auto;
}

dialog#torPreferences-requestBridge-dialog > hbox {
  margin-bottom: 1em;
}

/*
 Various elements that really should be lining up don't because they have inconsistent margins
*/
.torMarginFix {
  margin-left: 4px;
  margin-right: 4px;
}

/* Show bridge QR dialog */

#bridgeQr {
  flex: 0 0 auto;
  align-self: center;
  /* Some readers don't recognize QRs with inverted colors, so let's make
  the ones are darker than zeroes. See
  https://gitlab.torproject.org/tpo/applications/tor-browser/-/issues/41049 */
  --qr-one: black;
  --qr-zero: white;
  background: var(--qr-zero);
  /* Padding is needed in case the dark theme is used so the bits don't blend
  with whatever the default background color is. */
  padding: 10px;
  margin-block: 4px 8px;
  border-radius: var(--border-radius-small);
  display: grid;
  align-items: center;
  justify-items: center;
  grid-template: "qr" max-content / max-content;
}

#bridgeQr-target {
  width: 300px;
  height: 300px;
  background: var(--qr-zero);
  color: var(--qr-one);
  grid-area: qr;
}

#bridgeQr-icon {
  /* Share the same grid area as #bridgeQr-target. */
  grid-area: qr;
  content: url("chrome://browser/content/torpreferences/bridge.svg");
  padding: 10px;
  border-radius: var(--border-radius-medium);
  box-sizing: content-box;
  width: 52px;
  height: 52px;
  background: var(--qr-zero);
  -moz-context-properties: fill;
  fill: var(--qr-one);
}

/* Lox invite dialog */

#lox-invite-dialog-generate-area {
  flex: 0 0 auto;
  display: grid;
  grid-template:
    ". remaining button" min-content
    "message message message" auto
    / 1fr max-content max-content;
  gap: 8px;
  margin-block: 16px 8px;
  align-items: center;
}

#lox-invite-dialog-remaining {
  grid-area: remaining;
}

#lox-invite-dialog-generate-button {
  grid-area: button;
}

#lox-invite-dialog-message-area {
  grid-area: message;
  justify-self: end;
  display: flex;
  align-items: center;
}

#lox-invite-dialog-message-area::after {
  /* Zero width space, to ensure we are always one line high. */
  content: "\200B";
}

#lox-invite-dialog-error-message {
  color: var(--text-color-error);
}

#lox-invite-dialog-generate-area:not(.show-error) #lox-invite-dialog-error-message {
  display: none;
}

#lox-invite-dialog-connecting {
  color: var(--text-color-deemphasized);
  /* Gap with #user-provide-bridge-loading-icon. */
  margin-inline-start: 0.5em;
}

#lox-invite-dialog-generate-area:not(.show-connecting) #lox-invite-dialog-connecting {
  display: none;
}

#lox-invite-dialog-loading-icon {
  flex: 0 0 auto;
}

#lox-invite-dialog-generate-area:not(.show-connecting) #lox-invite-dialog-loading-icon {
  /* Use width:0 to effectively hide, but still occupy vertical space. */
  width: 0;
}

#lox-invite-dialog-list-label {
  font-weight: var(--font-weight-bold);
}

#lox-invite-dialog-list {
  flex: 1 1 auto;
  /* basis height */
  height: 10em;
  margin-block: 8px;
}

.lox-invite-dialog-list-item {
  white-space: nowrap;
  overflow-x: hidden;
  /* FIXME: ellipsis does not show. */
  text-overflow: ellipsis;
  padding-block: 6px;
  padding-inline: 8px;
}

/* Builtin bridge dialog */
#torPreferences-builtinBridge-header {
  margin: 8px 0 10px 0;
}

#torPreferences-builtinBridge-description {
  margin-bottom: 18px;
}

#torPreferences-builtinBridge-typeSelection {
  margin-bottom: 16px;
}

#torPreferences-builtinBridge-typeSelection radio label {
  font-weight: var(--font-weight-bold);
}

/* Request bridge dialog */
/*
  This hbox is hidden by css here by default so that the
  xul dialog allocates enough screen space for the error message
  element, otherwise it gets cut off since dialog's overflow is hidden
*/
hbox#torPreferences-requestBridge-incorrectCaptchaHbox {
  visibility: hidden;
}

image#torPreferences-requestBridge-errorIcon {
  list-style-image: url("chrome://global/skin/icons/warning.svg");
  -moz-context-properties: fill;
  fill: var(--icon-color-warning);
}

groupbox#torPreferences-bridges-group textarea {
  white-space: pre;
  overflow: auto;
}

/* Provide bridge dialog */

#user-provide-bridge-dialog:not(.show-entry-page) #user-provide-bridge-entry-page {
  display: none;
}

#user-provide-bridge-dialog:not(.show-result-page) #user-provide-bridge-result-page {
  display: none;
}

#user-provide-bridge-entry-page {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
}

#user-provide-bridge-description {
  flex: 0 0 auto;
}

#user-provide-bridge-textarea-label {
  margin-block: 16px 6px;
  flex: 0 0 auto;
  align-self: start;
}

#user-provide-bridge-textarea {
  flex: 1 0 auto;
  align-self: stretch;
  /* Only expect ASCII input, so can set a line-height. */
  line-height: 1.3;
  margin: 0;
}

#user-provide-bridge-message-area {
  flex: 0 0 auto;
  margin-block: 8px 12px;
  align-self: end;
  display: flex;
  align-items: center;
}

#user-provide-bridge-message-area::after {
  /* Zero width space, to ensure we are always one line high. */
  content: "\200B";
}

#user-provide-bridge-textarea.invalid-input {
  border-color: var(--outline-color-error);
  outline-color: var(--outline-color-error);
}

#user-provide-bridge-error-message {
  color: var(--text-color-error);
}

#user-provide-bridge-dialog:not(.show-error) #user-provide-bridge-error-message {
  display: none;
}

#user-provide-bridge-connecting {
  color: var(--text-color-deemphasized);
  /* Gap with #user-provide-bridge-loading-icon. */
  margin-inline-start: 0.5em;
}

#user-provide-bridge-dialog:not(.show-connecting) #user-provide-bridge-connecting {
  display: none;
}

#user-provide-bridge-loading-icon {
  flex: 0 0 auto;
}

#user-provide-bridge-dialog:not(.show-connecting) #user-provide-bridge-loading-icon {
  /* Use width:0 to effectively hide, but still occupy vertical space. */
  width: 0;
}

#user-provide-bridge-result-page {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

#user-provide-result-description {
  flex: 0 0 auto;
}

#user-provide-bridge-grid-display {
  flex: 0 1 auto;
  overflow: auto;
  margin-block: 8px;
}

#user-provide-bridge-grid-display:focus-visible {
  outline: var(--focus-outline);
  outline-offset: var(--focus-outline-offset);
}

/* Connection settings dialog */
#torPreferences-connection-dialog label {
  /* Do not wrap the labels. */
  white-space: nowrap;
}

#torPreferences-connection-header {
  margin: 4px 0 14px 0;
}

#torPreferences-connection-grid {
  display: grid;
  grid-template-columns: auto 1fr;
}

#torPreferences-localProxy-textboxAddress,
#torPreferences-localProxy-textboxUsername,
#torPreferences-localProxy-textboxPassword,
#torPreferences-connection-textboxAllowedPorts {
  flex: 1 0 auto;
}

#torPreferences-connection-firewall {
  display: flex;
}

#torPreferences-connection-hboxAllowedPorts {
  flex: 1;
}

/* Tor logs dialog */
#tor-log-table {
  flex: 1 0 auto;
  overflow: auto;
  min-height: 20em;
  height: 20em;
  display: flex;
  flex-direction: column;
  padding: var(--space-small);
  margin-block-end: 4px;
  border: 1px solid var(--border-color);
  border-radius: var(--border-radius-small);
  font-size: var(--font-size-small);
}

#tor-log-body,
#tor-log-table tr {
  display: contents;
}

#tor-log-table td {
  flex: 0 0 auto;
  padding: 0;
}

#tor-log-table td.time {
  color: var(--text-color-deemphasized);
  margin-block-end: var(--space-xsmall);
}

#tor-log-table td.message {
  overflow-wrap: anywhere;
}

#tor-log-table tr:not(:last-of-type) td.message {
  margin-block-end: var(--space-medium);
}
