Files
upstream-mirror a774ac673a
Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
snapshot of https://github.com/tldraw/tldraw.git (main, 2026-09-23; blobs > 131072B omitted)
2026-09-23 16:12:52 +05:00

1626 lines
52 KiB
CSS
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* @tldraw/editor */
.tl-container {
width: 100%;
height: 100%;
font-size: 12px;
/* Spacing */
--tl-space-1: 2px;
--tl-space-2: 4px;
--tl-space-3: 8px;
--tl-space-4: 12px;
--tl-space-5: 16px;
--tl-space-6: 20px;
--tl-space-7: 28px;
--tl-space-8: 32px;
--tl-space-9: 64px;
--tl-space-10: 72px;
/* Radius */
--tl-radius-0: 2px;
--tl-radius-1: 4px;
--tl-radius-2: 6px;
--tl-radius-3: 9px;
--tl-radius-4: 11px;
/*
* Canvas z-index
*
* .tl-canvas has `contain: strict` which creates its own stacking context.
* background, grid, shapes, overlays, and blocker are all children of .tl-canvas,
* so their z-indices are relative to the canvas, not the container.
*
* collaborators, watermark, and canvas-in-front are siblings of .tl-canvas
* (outside it), so they compete with the UI layer (.tlui-layout at z-index 300).
* canvas-in-front must be below the UI layer (300) to sit between
* the canvas and the UI; collaborator cursors sit above canvas content
* (and layers that anchor to it, like comment pins) but below the
* in-front content and the UI panels. The watermark (a licensing element)
* sits above that content so it can't be occluded, but still below the
* in-front content and the UI.
*/
--tl-layer-canvas-hidden: -999999;
--tl-layer-canvas-background: 100;
--tl-layer-canvas-grid: 150;
--tl-layer-collaborators: 245;
--tl-layer-watermark: 248;
--tl-layer-canvas-in-front: 250;
--tl-layer-canvas-shapes: 300;
--tl-layer-canvas-overlays: 500;
--tl-layer-canvas-blocker: 10000;
/* Canvas overlays z-index */
--tl-layer-overlays-collaborator-scribble: 10;
--tl-layer-overlays-collaborator-brush: 20;
--tl-layer-overlays-collaborator-shape-indicator: 30;
--tl-layer-overlays-user-scribble: 40;
--tl-layer-overlays-user-brush: 50;
--tl-layer-overlays-user-snapline: 90;
--tl-layer-overlays-selection-fg: 100;
/* User handles need to be above selection edges / corners, matters for sticky note clone handles */
--tl-layer-overlays-user-handles: 105;
--tl-layer-overlays-user-indicator-hint: 110;
--tl-layer-overlays-collaborator-cursor-hint: 120;
--tl-layer-overlays-collaborator-cursor: 130;
/* Text editor z-index */
--tl-layer-text-container: 1;
--tl-layer-text-content: 3;
--tl-layer-text-editor: 4;
/* Error fallback z-index */
--tl-layer-error-overlay: 1;
--tl-layer-error-canvas: 2;
--tl-layer-error-canvas-after: 3;
--tl-layer-error-content: 4;
/* Misc */
--tl-zoom: 1;
--tl-tab-size: 2;
/* Cursor SVGs */
--tl-cursor-none: none;
--tl-cursor-default:
url("data:image/svg+xml,<svg height='32' width='32' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg' style='color: black;'><defs><filter id='shadow' y='-40%' x='-40%' width='180px' height='180%' color-interpolation-filters='sRGB'><feDropShadow dx='1' dy='1' stdDeviation='1.2' flood-opacity='.5'/></filter></defs><g fill='none' transform='rotate(0 16 16)' filter='url(%23shadow)'><path d='m12 24.4219v-16.015l11.591 11.619h-6.781l-.411.124z' fill='white'/><path d='m21.0845 25.0962-3.605 1.535-4.682-11.089 3.686-1.553z' fill='white'/><path d='m19.751 24.4155-1.844.774-3.1-7.374 1.841-.775z' fill='black'/><path d='m13 10.814v11.188l2.969-2.866.428-.139h4.768z' fill='black'/></g></svg>")
12 8,
default;
--tl-cursor-pointer:
url("data:image/svg+xml,<svg height='32' width='32' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg' style='color: black;'><defs><filter id='shadow' y='-40%' x='-40%' width='180px' height='180%' color-interpolation-filters='sRGB'><feDropShadow dx='1' dy='1' stdDeviation='1.2' flood-opacity='.5'/></filter></defs><g fill='none' transform='rotate(0 16 16)' filter='url(%23shadow)'><path d='m13.3315 21.3799c-.284-.359-.629-1.093-1.243-1.984-.348-.504-1.211-1.453-1.468-1.935-.223-.426-.199-.617-.146-.97.094-.628.738-1.117 1.425-1.051.519.049.959.392 1.355.716.239.195.533.574.71.788.163.196.203.277.377.509.23.307.302.459.214.121-.071-.496-.187-1.343-.355-2.092-.128-.568-.159-.657-.281-1.093-.129-.464-.195-.789-.316-1.281-.084-.348-.235-1.059-.276-1.459-.057-.547-.087-1.439.264-1.849.275-.321.906-.418 1.297-.22.512.259.803 1.003.936 1.3.239.534.387 1.151.516 1.961.164 1.031.466 2.462.476 2.763.024-.369-.068-1.146-.004-1.5.058-.321.328-.694.666-.795.286-.085.621-.116.916-.055.313.064.643.288.766.499.362.624.369 1.899.384 1.831.086-.376.071-1.229.284-1.584.14-.234.497-.445.687-.479.294-.052.655-.068.964-.008.249.049.586.345.677.487.218.344.342 1.317.379 1.658.015.141.074-.392.293-.736.406-.639 1.843-.763 1.898.639.025.654.02.624.02 1.064 0 .517-.012.828-.04 1.202-.031.4-.117 1.304-.242 1.742-.086.301-.371.978-.652 1.384 0 0-1.074 1.25-1.191 1.813-.118.562-.079.566-.102.965-.023.398.121.922.121.922s-.802.104-1.234.035c-.391-.063-.875-.841-1-1.079-.172-.328-.539-.265-.682-.023-.225.383-.709 1.07-1.051 1.113-.668.084-2.054.031-3.139.02 0 0 .185-1.011-.227-1.358-.305-.259-.83-.784-1.144-1.06z' fill='white'/><g stroke='black' stroke-linecap='round' stroke-width='.75'><path d='m13.3315 21.3799c-.284-.359-.629-1.093-1.243-1.984-.348-.504-1.211-1.453-1.468-1.935-.223-.426-.199-.617-.146-.97.094-.628.738-1.117 1.425-1.051.519.049.959.392 1.355.716.239.195.533.574.71.788.163.196.203.277.377.509.23.307.302.459.214.121-.071-.496-.187-1.343-.355-2.092-.128-.568-.159-.657-.281-1.093-.129-.464-.195-.789-.316-1.281-.084-.348-.235-1.059-.276-1.459-.057-.547-.087-1.439.264-1.849.275-.321.906-.418 1.297-.22.512.259.803 1.003.936 1.3.239.534.387 1.151.516 1.961.164 1.031.466 2.462.476 2.763.024-.369-.068-1.146-.004-1.5.058-.321.328-.694.666-.795.286-.085.621-.116.916-.055.313.064.643.288.766.499.362.624.369 1.899.384 1.831.086-.376.071-1.229.284-1.584.14-.234.497-.445.687-.479.294-.052.655-.068.964-.008.249.049.586.345.677.487.218.344.342 1.317.379 1.658.015.141.074-.392.293-.736.406-.639 1.843-.763 1.898.639.025.654.02.624.02 1.064 0 .517-.012.828-.04 1.202-.031.4-.117 1.304-.242 1.742-.086.301-.371.978-.652 1.384 0 0-1.074 1.25-1.191 1.813-.118.562-.079.566-.102.965-.023.398.121.922.121.922s-.802.104-1.234.035c-.391-.063-.875-.841-1-1.079-.172-.328-.539-.265-.682-.023-.225.383-.709 1.07-1.051 1.113-.668.084-2.054.031-3.139.02 0 0 .185-1.011-.227-1.358-.305-.259-.83-.784-1.144-1.06z' stroke-linejoin='round'/><path d='m21.5664 21.7344v-3.459'/><path d='m19.5508 21.7461-.016-3.473'/><path d='m17.5547 18.3047.021 3.426'/></g></g></svg>")
14 10,
pointer;
--tl-cursor-cross:
url("data:image/svg+xml,<svg height='32' width='32' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg' style='color: black;'><defs><filter id='shadow' y='-40%' x='-40%' width='180px' height='180%' color-interpolation-filters='sRGB'><feDropShadow dx='1' dy='1' stdDeviation='1.2' flood-opacity='.5'/></filter></defs><g fill='none' transform='rotate(0 16 16)' filter='url(%23shadow)'><path d='m25 16h-6.01v-6h-2.98v6h-6.01v3h6.01v6h2.98v-6h6.01z' fill='white'/><path d='m23.9902 17.0103h-6v-6.01h-.98v6.01h-6v.98h6v6.01h.98v-6.01h6z' fill='%23231f1f'/></g></svg>")
16 16,
crosshair;
--tl-cursor-comment:
url("data:image/svg+xml,<svg height='32' width='32' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'><defs><filter id='shadow' y='-40%' x='-40%' width='180px' height='180%' color-interpolation-filters='sRGB'><feDropShadow dx='1' dy='1' stdDeviation='1.2' flood-opacity='.5'/></filter></defs><g filter='url(%23shadow)'><path d='M5 19.5 L5 11 A8 8 0 0 1 13 3 A8 8 0 0 1 21 11 A8 8 0 0 1 13 19 Z' fill='white' stroke='black' stroke-width='1' stroke-linejoin='round'/></g></svg>")
5 19,
crosshair;
--tl-cursor-move:
url("data:image/svg+xml,<svg height='32' width='32' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg' style='color: black;'><defs><filter id='shadow' y='-40%' x='-40%' width='180px' height='180%' color-interpolation-filters='sRGB'><feDropShadow dx='1' dy='1' stdDeviation='1.2' flood-opacity='.5'/></filter></defs><g fill='none' transform='rotate(0 16 16)' filter='url(%23shadow)'><path d='m19 14h1v1h-1zm1 6h-1v-1h1zm-5-5h-1v-1h1zm0 5h-1v-1h1zm2-10.987-7.985 7.988 5.222 5.221 2.763 2.763 7.984-7.985z' fill='white'/><g fill='black'><path d='m23.5664 16.9971-2.557-2.809v1.829h-4.009-4.001v-1.829l-2.571 2.809 2.572 2.808-.001-1.808h4.001 4.009l-.001 1.808z'/><path d='m17.9873 17h.013v-4.001l1.807.001-2.807-2.571-2.809 2.57h1.809v4.001h.008v4.002l-1.828-.001 2.807 2.577 2.805-2.576h-1.805z'/></g></g></svg>")
16 16,
move;
--tl-cursor-grab:
url("data:image/svg+xml,<svg height='32' width='32' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg' style='color: black;'><defs><filter id='shadow' y='-40%' x='-40%' width='180px' height='180%' color-interpolation-filters='sRGB'><feDropShadow dx='1' dy='1' stdDeviation='1.2' flood-opacity='.5'/></filter></defs><g fill='none' transform='rotate(0 16 16)' filter='url(%23shadow)'><path d='m13.5557 17.5742c-.098-.375-.196-.847-.406-1.552-.167-.557-.342-.859-.47-1.233-.155-.455-.303-.721-.496-1.181-.139-.329-.364-1.048-.457-1.44-.119-.509.033-.924.244-1.206.253-.339.962-.49 1.357-.351.371.13.744.512.916.788.288.46.357.632.717 1.542.393.992.564 1.918.611 2.231l.085.452c-.001-.04-.043-1.122-.044-1.162-.035-1.029-.06-1.823-.038-2.939.002-.126.064-.587.084-.715.078-.5.305-.8.673-.979.412-.201.926-.215 1.401-.017.423.173.626.55.687 1.022.014.109.094.987.093 1.107-.013 1.025.006 1.641.015 2.174.004.231.003 1.625.017 1.469.061-.656.094-3.189.344-3.942.144-.433.405-.746.794-.929.431-.203 1.113-.07 1.404.243.285.305.446.692.482 1.153.032.405-.019.897-.02 1.245 0 .867-.021 1.324-.037 2.121-.001.038-.015.298.023.182.094-.28.188-.542.266-.745.049-.125.241-.614.359-.859.114-.234.211-.369.415-.688.2-.313.415-.448.668-.561.54-.235 1.109.112 1.301.591.086.215.009.713-.028 1.105-.061.647-.254 1.306-.352 1.648-.128.447-.274 1.235-.34 1.601-.072.394-.234 1.382-.359 1.82-.086.301-.371.978-.652 1.384 0 0-1.074 1.25-1.192 1.812-.117.563-.078.567-.101.965-.024.399.121.923.121.923s-.802.104-1.234.034c-.391-.062-.875-.841-1-1.078-.172-.328-.539-.265-.682-.023-.225.383-.709 1.07-1.051 1.113-.668.084-2.054.03-3.139.02 0 0 .185-1.011-.227-1.358-.305-.26-.83-.784-1.144-1.06l-.832-.921c-.284-.36-.629-1.093-1.243-1.985-.348-.504-1.027-1.085-1.284-1.579-.223-.425-.331-.954-.19-1.325.225-.594.675-.897 1.362-.832.519.05.848.206 1.238.537.225.19.573.534.75.748.163.195.203.276.377.509.23.307.302.459.214.121' fill='white'/><g stroke='black' stroke-linecap='round' stroke-width='.75'><path d='m13.5557 17.5742c-.098-.375-.196-.847-.406-1.552-.167-.557-.342-.859-.47-1.233-.155-.455-.303-.721-.496-1.181-.139-.329-.364-1.048-.457-1.44-.119-.509.033-.924.244-1.206.253-.339.962-.49 1.357-.351.371.13.744.512.916.788.288.46.357.632.717 1.542.393.992.564 1.918.611 2.231l.085.452c-.001-.04-.043-1.122-.044-1.162-.035-1.029-.06-1.823-.038-2.939.002-.126.064-.587.084-.715.078-.5.305-.8.673-.979.412-.201.926-.215 1.401-.017.423.173.626.55.687 1.022.014.109.094.987.093 1.107-.013 1.025.006 1.641.015 2.174.004.231.003 1.625.017 1.469.061-.656.094-3.189.344-3.942.144-.433.405-.746.794-.929.431-.203 1.113-.07 1.404.243.285.305.446.692.482 1.153.032.405-.019.897-.02 1.245 0 .867-.021 1.324-.037 2.121-.001.038-.015.298.023.182.094-.28.188-.542.266-.745.049-.125.241-.614.359-.859.114-.234.211-.369.415-.688.2-.313.415-.448.668-.561.54-.235 1.109.112 1.301.591.086.215.009.713-.028 1.105-.061.647-.254 1.306-.352 1.648-.128.447-.274 1.235-.34 1.601-.072.394-.234 1.382-.359 1.82-.086.301-.371.978-.652 1.384 0 0-1.074 1.25-1.192 1.812-.117.563-.078.567-.101.965-.024.399.121.923.121.923s-.802.104-1.234.034c-.391-.062-.875-.841-1-1.078-.172-.328-.539-.265-.682-.023-.225.383-.709 1.07-1.051 1.113-.668.084-2.054.03-3.139.02 0 0 .185-1.011-.227-1.358-.305-.26-.83-.784-1.144-1.06l-.832-.921c-.284-.36-.629-1.093-1.243-1.985-.348-.504-1.027-1.085-1.284-1.579-.223-.425-.331-.954-.19-1.325.225-.594.675-.897 1.362-.832.519.05.848.206 1.238.537.225.19.573.534.75.748.163.195.203.276.377.509.23.307.302.459.214.121' stroke-linejoin='round'/><path d='m20.5664 21.7344v-3.459'/><path d='m18.5508 21.7461-.016-3.473'/><path d='m16.5547 18.3047.021 3.426'/></g></g></svg>")
16 16,
grab;
--tl-cursor-grabbing:
url("data:image/svg+xml,<svg height='32' width='32' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg' style='color: black;'><defs><filter id='shadow' y='-40%' x='-40%' width='180px' height='180%' color-interpolation-filters='sRGB'><feDropShadow dx='1' dy='1' stdDeviation='1.2' flood-opacity='.5'/></filter></defs><g fill='none' transform='rotate(0 16 16)' filter='url(%23shadow)'><path d='m13.5732 12.0361c.48-.178 1.427-.069 1.677.473.213.462.396 1.241.406 1.075.024-.369-.024-1.167.137-1.584.117-.304.347-.59.686-.691.285-.086.62-.116.916-.055.313.064.642.287.765.499.362.623.368 1.899.385 1.831.064-.272.07-1.229.283-1.584.141-.235.497-.445.687-.479.294-.052.656-.068.964-.008.249.049.586.344.677.487.219.344.342 1.316.379 1.658.016.141.074-.393.293-.736.406-.639 1.844-.763 1.898.639.026.654.02.624.02 1.064 0 .516-.012.828-.04 1.202-.03.399-.116 1.304-.241 1.742-.086.301-.371.978-.653 1.384 0 0-1.074 1.25-1.191 1.812-.117.563-.078.567-.102.965-.023.399.121.923.121.923s-.801.104-1.234.034c-.391-.062-.875-.84-1-1.078-.172-.328-.539-.265-.682-.023-.224.383-.709 1.07-1.05 1.113-.669.084-2.055.03-3.14.02 0 0 .185-1.011-.227-1.358-.305-.26-.83-.784-1.144-1.06l-.832-.921c-.283-.36-1.002-.929-1.243-1.985-.213-.936-.192-1.395.037-1.77.232-.381.67-.589.854-.625.208-.042.692-.039.875.062.223.123.313.159.488.391.23.307.312.456.213.121-.076-.262-.322-.595-.434-.97-.109-.361-.401-.943-.38-1.526.008-.221.103-.771.832-1.042' fill='white'/><g stroke='black' stroke-width='.75'><path d='m13.5732 12.0361c.48-.178 1.427-.069 1.677.473.213.462.396 1.241.406 1.075.024-.369-.024-1.167.137-1.584.117-.304.347-.59.686-.691.285-.086.62-.116.916-.055.313.064.642.287.765.499.362.623.368 1.899.385 1.831.064-.272.07-1.229.283-1.584.141-.235.497-.445.687-.479.294-.052.656-.068.964-.008.249.049.586.344.677.487.219.344.342 1.316.379 1.658.016.141.074-.393.293-.736.406-.639 1.844-.763 1.898.639.026.654.02.624.02 1.064 0 .516-.012.828-.04 1.202-.03.399-.116 1.304-.241 1.742-.086.301-.371.978-.653 1.384 0 0-1.074 1.25-1.191 1.812-.117.563-.078.567-.102.965-.023.399.121.923.121.923s-.801.104-1.234.034c-.391-.062-.875-.84-1-1.078-.172-.328-.539-.265-.682-.023-.224.383-.709 1.07-1.05 1.113-.669.084-2.055.03-3.14.02 0 0 .185-1.011-.227-1.358-.305-.26-.83-.784-1.144-1.06l-.832-.921c-.283-.36-1.002-.929-1.243-1.985-.213-.936-.192-1.395.037-1.77.232-.381.67-.589.854-.625.208-.042.692-.039.875.062.223.123.313.159.488.391.23.307.312.456.213.121-.076-.262-.322-.595-.434-.97-.109-.361-.401-.943-.38-1.526.008-.221.103-.771.832-1.042z' stroke-linejoin='round'/><path d='m20.5664 19.7344v-3.459' stroke-linecap='round'/><path d='m18.5508 19.7461-.016-3.473' stroke-linecap='round'/><path d='m16.5547 16.3047.021 3.426' stroke-linecap='round'/></g></g></svg>")
16 16,
grabbing;
--tl-cursor-text:
url("data:image/svg+xml,<svg height='32' width='32' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg' style='color: black;'><defs><filter id='shadow' y='-40%' x='-40%' width='180px' height='180%' color-interpolation-filters='sRGB'><feDropShadow dx='1' dy='1' stdDeviation='1.2' flood-opacity='.5'/></filter></defs><g fill='none' transform='rotate(0 16 16)' filter='url(%23shadow)'><path fill='white' d='M7.94 0a5.25 5.25 0 0 0-3.47 1.17A5.27 5.27 0 0 0 1 0H0v3h1c1.41 0 1.85.7 2 1v3.94H2v3h1v3c-.13.3-.57 1-2 1H0v3h1a5.27 5.27 0 0 0 3.47-1.17c.98.8 2.21 1.21 3.47 1.17h1v-3h-1c-1.41 0-1.85-.7-2-1v-3H7v-3H6V4c.13-.3.57-1 2-1h1V0H7.94z'/><path fill='black' d='M7.94 2V1a4 4 0 0 0-3.47 1.64A4 4 0 0 0 1 1v1c1.3-.17 2.56.6 3 1.84v5.1H3v1h1v4.16c-.45 1.24-1.7 2-3 1.84v1a4.05 4.05 0 0 0 3.47-1.63 4.05 4.05 0 0 0 3.47 1.63v-1A2.82 2.82 0 0 1 5 14.1V9.93h1v-1H5V3.85A2.81 2.81 0 0 1 7.94 2z'/></g></svg>")
4 10,
text;
--tl-cursor-zoom-in:
url("data:image/svg+xml,<svg height='32' width='32' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg' style='color: black;'><defs><filter id='shadow' y='-40%' x='-40%' width='180px' height='180%' color-interpolation-filters='sRGB'><feDropShadow dx='1' dy='1' stdDeviation='1.2' flood-opacity='.5'/></filter></defs><g fill='none' transform='rotate(0 16 16)' filter='url(%23shadow)'><path d='m20.5 15c0 3.038-2.462 5.5-5.5 5.5s-5.5-2.462-5.5-5.5 2.462-5.5 5.5-5.5 5.5 2.462 5.5 5.5' fill='white'/><path d='m20.5 15c0 3.038-2.462 5.5-5.5 5.5s-5.5-2.462-5.5-5.5 2.462-5.5 5.5-5.5 5.5 2.462 5.5 5.5z' stroke='black'/><g fill='black'><path d='m18 14h-2v-2h-2v2h-2v1.98h2v2.02h2v-2.02h2z'/><path d='m23.5859 25 1.414-1.414-5.449-5.449-1.414 1.414z'/></g></g></svg>")
16 16,
zoom-in;
--tl-cursor-zoom-out:
url("data:image/svg+xml,<svg height='32' width='32' viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg' style='color: black;'><defs><filter id='shadow' y='-40%' x='-40%' width='180px' height='180%' color-interpolation-filters='sRGB'><feDropShadow dx='1' dy='1' stdDeviation='1.2' flood-opacity='.5'/></filter></defs><g fill='none' transform='rotate(0 16 16)' filter='url(%23shadow)'><path d='m20.5 15c0 3.038-2.462 5.5-5.5 5.5s-5.5-2.462-5.5-5.5 2.462-5.5 5.5-5.5 5.5 2.462 5.5 5.5' fill='white'/><path d='m20.5 15c0 3.038-2.462 5.5-5.5 5.5s-5.5-2.462-5.5-5.5 2.462-5.5 5.5-5.5 5.5 2.462 5.5 5.5z' stroke='black'/><g fill='black'><path d='m18 16h-5.98v-1.98h5.98z'/><path d='m23.5859 25 1.414-1.414-5.449-5.449-1.414 1.414z'/></g></g></svg>")
16 16,
zoom-out;
/* These cursor values get programmatically overridden */
/* They're just here to help your editor autocomplete */
--tl-cursor: var(--tl-cursor-default);
--tl-cursor-resize-edge: ew-resize;
--tl-cursor-resize-corner: nesw-resize;
--tl-cursor-ew-resize: ew-resize;
--tl-cursor-ns-resize: ns-resize;
--tl-cursor-nesw-resize: nesw-resize;
--tl-cursor-nwse-resize: nwse-resize;
--tl-cursor-rotate: pointer;
--tl-cursor-nwse-rotate: pointer;
--tl-cursor-nesw-rotate: pointer;
--tl-cursor-senw-rotate: pointer;
--tl-cursor-swne-rotate: pointer;
--tl-scale: calc(1 / var(--tl-zoom));
/* fonts */
--tl-font-draw: 'tldraw_draw', sans-serif;
--tl-font-sans: 'tldraw_sans', sans-serif;
--tl-font-serif: 'tldraw_serif', serif;
--tl-font-mono: 'tldraw_mono', monospace;
/* text outline */
--tl-text-outline-a: calc(min(0.5, 1 / var(--tl-zoom)) * 2px);
--tl-text-outline-b: calc(min(0.5, 1 / var(--tl-zoom)) * -2px);
--tl-text-outline-reference:
0 var(--tl-text-outline-b) 0 var(--tl-color-background),
0 var(--tl-text-outline-a) 0 var(--tl-color-background),
var(--tl-text-outline-b) var(--tl-text-outline-b) 0 var(--tl-color-background),
var(--tl-text-outline-a) var(--tl-text-outline-b) 0 var(--tl-color-background),
var(--tl-text-outline-a) var(--tl-text-outline-a) 0 var(--tl-color-background),
var(--tl-text-outline-b) var(--tl-text-outline-a) 0 var(--tl-color-background);
--tl-text-outline: var(--tl-text-outline-reference);
/* own properties */
position: relative;
inset: 0px;
height: 100%;
width: 100%;
overflow: clip;
color: var(--tl-color-text);
}
.tl-theme__light {
/* Canvas */
--tl-color-selection-fill: hsl(210, 100%, 56%, 24%);
--tl-color-selection-stroke: hsl(214, 84%, 56%);
--tl-color-background: hsl(210, 20%, 98%);
/* if you ever update --tl-color-background, update the hardcoded values in theme-init.js and globals.css
they're there to make sure the background color matches the user's preference before the actual app loads*/
--tl-color-grid: hsl(0, 0%, 43%);
/* UI */
--tl-color-low: hsl(204, 16%, 94%);
--tl-color-low-border: hsl(204, 16%, 92%);
--tl-color-muted-none: hsl(0, 0%, 0%, 0%);
--tl-color-muted-0: hsl(0, 0%, 0%, 2%);
--tl-color-muted-1: hsl(0, 0%, 0%, 10%);
--tl-color-muted-2: hsl(0, 0%, 0%, 4.3%);
--tl-color-hint: hsl(0, 0%, 0%, 5.5%);
--tl-color-overlay: hsl(0, 0%, 0%, 20%);
--tl-color-divider: hsl(0, 0%, 91%);
--tl-color-panel: hsl(0, 0%, 99%);
--tl-color-panel-contrast: hsl(0, 0%, 100%);
--tl-color-panel-overlay: hsl(0, 0%, 100%, 82%);
--tl-color-panel-transparent: hsla(0, 0%, 99%, 0%);
--tl-color-selected: hsl(214, 84%, 56%);
--tl-color-selected-contrast: hsl(0, 0%, 100%);
--tl-color-focus: hsl(219, 65%, 50%);
--tl-color-tooltip: hsla(200, 14%, 4%, 1);
/* Text */
--tl-color-text: hsl(0, 0%, 0%);
--tl-color-text-0: hsl(0, 0%, 11%);
--tl-color-text-1: hsl(0, 0%, 18%);
--tl-color-text-3: hsl(204, 4%, 45%);
--tl-color-text-disabled: hsl(204, 4%, 55%);
--tl-color-text-shadow: hsl(0, 0%, 100%);
--tl-color-text-highlight: hsl(52, 100%, 50%);
--tl-color-text-highlight-p3: color(display-p3 0.972 0.8205 0.05);
/* Named */
--tl-color-primary: hsl(214, 84%, 56%);
--tl-color-success: hsl(123, 46%, 34%);
--tl-color-info: hsl(201, 98%, 41%);
--tl-color-warning: hsl(27, 98%, 47%);
--tl-color-danger: hsl(0, 90%, 43%);
/* Shadows */
--tl-shadow-1: 0px 1px 2px hsl(0, 0%, 0%, 25%), 0px 1px 3px hsl(0, 0%, 0%, 9%);
--tl-shadow-2:
0px 0px 2px hsl(0, 0%, 0%, 16%), 0px 2px 3px hsl(0, 0%, 0%, 24%),
0px 2px 6px hsl(0, 0%, 0%, 0.1), inset 0px 0px 0px 1px var(--tl-color-panel-contrast);
--tl-shadow-3:
0px 1px 2px hsl(0, 0%, 0%, 28%), 0px 2px 6px hsl(0, 0%, 0%, 14%),
inset 0px 0px 0px 1px var(--tl-color-panel-contrast);
--tl-shadow-4:
0px 0px 3px hsl(0, 0%, 0%, 19%), 0px 5px 4px hsl(0, 0%, 0%, 16%),
0px 2px 16px hsl(0, 0%, 0%, 6%), inset 0px 0px 0px 1px var(--tl-color-panel-contrast);
}
.tl-theme__dark {
/* Canvas */
--tl-color-selection-fill: hsl(209, 100%, 57%, 20%);
--tl-color-selection-stroke: hsl(214, 84%, 56%);
--tl-color-background: hsl(240, 5%, 6.5%);
/* if you ever update --tl-color-background, update the hardcoded values in theme-init.js and globals.css
they're there to make sure the background color matches the user's preference before the actual app loads*/
--tl-color-grid: hsl(0, 0%, 40%);
/* UI */
--tl-color-low: hsl(260, 4.5%, 10.5%);
--tl-color-low-border: hsl(207, 10%, 10%);
--tl-color-muted-none: hsl(0, 0%, 100%, 0%);
--tl-color-muted-0: hsl(0, 0%, 100%, 2%);
--tl-color-muted-1: hsl(0, 0%, 100%, 10%);
--tl-color-muted-2: hsl(0, 0%, 100%, 5%);
--tl-color-hint: hsl(0, 0%, 100%, 7%);
--tl-color-overlay: hsl(0, 0%, 0%, 50%);
--tl-color-divider: hsl(240, 9%, 22%);
--tl-color-panel: hsl(235, 6.8%, 13.5%);
--tl-color-panel-contrast: hsl(245, 12%, 23%);
--tl-color-panel-overlay: hsl(210, 10%, 24%, 82%);
--tl-color-panel-transparent: hsla(235, 6.8%, 13.5%, 0%);
--tl-color-selected: hsl(217, 89%, 61%);
--tl-color-selected-contrast: hsl(0, 0%, 100%);
--tl-color-focus: hsl(217, 76%, 80%);
--tl-color-tooltip: hsla(0, 0%, 100%, 1);
/* Text */
--tl-color-text: hsl(210, 17%, 98%);
--tl-color-text-0: hsl(0, 9%, 94%);
--tl-color-text-1: hsl(0, 0%, 85%);
--tl-color-text-3: hsl(204, 4%, 75%);
--tl-color-text-disabled: hsl(204, 4%, 50%);
--tl-color-text-shadow: hsl(210, 13%, 18%);
--tl-color-text-highlight: hsl(52, 100%, 41%);
--tl-color-text-highlight-p3: color(display-p3 0.8078 0.6225 0.0312);
/* Named */
--tl-color-primary: hsl(214, 84%, 56%);
--tl-color-success: hsl(123, 38%, 57%);
--tl-color-info: hsl(199, 92%, 56%);
--tl-color-warning: hsl(36, 100%, 57%);
--tl-color-danger: hsl(0, 82%, 66%);
/* Shadows */
--tl-shadow-1:
0px 1px 2px hsl(0, 0%, 0%, 16.1%), 0px 1px 3px hsl(0, 0%, 0%, 22%),
inset 0px 0px 0px 1px var(--tl-color-panel-contrast);
--tl-shadow-2:
0px 1px 3px hsl(0, 0%, 0%, 66.6%), 0px 2px 6px hsl(0, 0%, 0%, 33%),
inset 0px 0px 0px 1px var(--tl-color-panel-contrast);
--tl-shadow-3:
0px 1px 3px hsl(0, 0%, 0%, 50%), 0px 2px 12px hsl(0, 0%, 0%, 50%),
inset 0px 0px 0px 1px var(--tl-color-panel-contrast);
}
.tl-counter-scaled {
transform: scale(var(--tl-scale));
transform-origin: top left;
width: calc(100% * var(--tl-zoom));
height: calc(100% * var(--tl-zoom));
}
.tl-container,
.tl-container * {
-webkit-touch-callout: none;
-webkit-tap-highlight-color: transparent;
scrollbar-highlight-color: transparent;
-webkit-user-select: none;
user-select: none;
box-sizing: border-box;
outline: none;
}
.tl-container a {
-webkit-touch-callout: initial;
}
.tl-container__focused {
outline: 1px solid var(--tl-color-low);
}
/* The host for <EditorPortal>, last among the container's children. It's a position in the DOM
rather than a box: `display: contents` keeps what it holds positioned against the container. */
.tl-portal-host {
display: contents;
}
input,
*[contenteditable],
*[contenteditable] * {
user-select: text;
}
/* --------------------- Canvas --------------------- */
.tl-canvas {
position: absolute;
inset: 0px;
height: 100%;
width: 100%;
color: var(--tl-color-text);
cursor: var(--tl-cursor);
overflow: clip;
content-visibility: auto;
touch-action: none;
contain: strict;
}
.tl-canvas__in-front {
position: absolute;
inset: 0;
pointer-events: none;
z-index: var(--tl-layer-canvas-in-front);
}
.tl-shapes {
position: relative;
z-index: var(--tl-layer-canvas-shapes);
}
.tl-svg-context {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
pointer-events: none;
}
/* ------------------- Background ------------------- */
.tl-background__wrapper {
z-index: var(--tl-layer-canvas-background);
position: absolute;
inset: 0px;
height: 100%;
width: 100%;
}
.tl-background {
background-color: var(--tl-color-background);
width: 100%;
height: 100%;
}
/* --------------------- Grid Layer --------------------- */
.tl-grid {
position: absolute;
inset: 0px;
width: 100%;
height: 100%;
touch-action: none;
pointer-events: none;
z-index: var(--tl-layer-canvas-grid);
contain: strict;
}
.tl-grid-dot {
fill: var(--tl-color-grid);
}
/* --------------------- Layers --------------------- */
.tl-html-layer {
position: absolute;
top: 0px;
left: 0px;
width: 1px;
height: 1px;
contain: layout style size;
}
/* The collaborator cursor layer: a sibling of .tl-canvas, above all canvas content, below the
in-front layer (250) and the UI panels (300). Display-only — pointer events pass through. */
.tl-collaborators {
position: absolute;
inset: 0px;
z-index: var(--tl-layer-collaborators);
pointer-events: none;
overflow: clip;
contain: layout style size;
}
.tl-collaborators__item {
position: absolute;
top: 0px;
left: 0px;
overflow: visible;
pointer-events: none;
transform-origin: top left;
}
.tl-cursor {
overflow: visible;
}
/* --------------- Overlay Stack --------------- */
/* -------------- Selection foreground -------------- */
.tl-selection__bg {
position: absolute;
top: 0px;
left: 0px;
transform-origin: top left;
background-color: transparent;
pointer-events: all;
}
.tl-transparent {
fill: transparent;
stroke: transparent;
}
.tl-hidden {
opacity: 0;
pointer-events: none;
}
/* -------------- Nametag / cursor chat ------------- */
.tl-nametag {
position: absolute;
top: 16px;
left: 13px;
width: fit-content;
height: fit-content;
max-width: 120px;
padding: 3px 6px;
white-space: nowrap;
position: absolute;
overflow: hidden;
text-overflow: ellipsis;
font-size: 12px;
border-radius: var(--tl-radius-2);
color: var(--tl-color-selected-contrast);
}
.tl-nametag-title {
position: absolute;
top: -2px;
left: 13px;
width: fit-content;
height: fit-content;
padding: 0px 6px;
max-width: 120px;
white-space: nowrap;
position: absolute;
overflow: hidden;
text-overflow: ellipsis;
font-size: 12px;
text-shadow: var(--tl-text-outline);
color: var(--tl-color-selected-contrast);
}
.tl-nametag-chat {
position: absolute;
top: 16px;
left: 13px;
width: fit-content;
height: fit-content;
color: var(--tl-color-selected-contrast);
white-space: nowrap;
position: absolute;
padding: 3px 6px;
font-size: 12px;
opacity: 1;
border-radius: var(--tl-radius-2);
}
.tl-cursor-chat {
position: absolute;
color: var(--tl-color-selected-contrast);
white-space: nowrap;
padding: 3px 6px;
font-size: 12px;
pointer-events: none;
z-index: var(--tl-layer-cursor);
margin-top: 16px;
margin-left: 13px;
opacity: 1;
border: none;
user-select: text;
border-radius: var(--tl-radius-2);
}
.tl-cursor-chat .tl-cursor-chat__bubble {
padding-right: 12px;
}
.tl-cursor-chat::selection {
background: var(--tl-color-selected);
color: var(--tl-color-selected-contrast);
text-shadow: none;
}
.tl-cursor-chat::placeholder {
color: var(--tl-color-selected-contrast);
opacity: 0.7;
}
/* ---------------------- Text ---------------------- */
.tl-text-shape-label {
position: relative;
font-weight: normal;
min-width: 1px;
padding: 0px;
margin: 0px;
border: none;
width: fit-content;
height: fit-content;
font-variant: normal;
font-style: normal;
pointer-events: all;
white-space: pre-wrap;
overflow-wrap: break-word;
}
.tl-plain-text-wrapper[data-isediting='true'] .tl-text-content {
opacity: 0;
}
.tl-rich-text-wrapper[data-isediting='true'] .tl-text-content {
display: none;
}
.tl-text {
/* remove overflow from textarea on windows */
margin: 0px;
padding: 0px;
appearance: auto;
background: none;
border-image: none;
border: 0px;
caret-color: var(--tl-color-text);
color: inherit;
column-count: initial !important;
display: inline-block;
font-family: inherit;
font-feature-settings: normal;
font-kerning: auto;
font-optical-sizing: auto;
font-size: inherit;
font-stretch: 100%;
font-style: inherit;
font-variant: inherit;
font-variation-settings: normal;
font-weight: inherit;
letter-spacing: inherit;
line-height: inherit;
outline: none;
overflow-wrap: break-word;
text-align: inherit;
text-indent: 0px;
text-rendering: auto;
text-shadow: inherit;
text-transform: none;
white-space: pre-wrap;
line-break: normal;
word-spacing: 0px;
word-wrap: break-word;
writing-mode: horizontal-tb !important;
}
.tl-text-measure {
z-index: var(--tl-layer-canvas-hidden);
opacity: 0;
visibility: hidden;
/* pointer-events: all; */
/* opacity: 1; */
/* z-index: 99999; */
position: absolute;
top: 0px;
left: 0px;
width: max-content;
box-sizing: border-box;
pointer-events: none;
white-space: pre-wrap;
word-wrap: break-word;
overflow-wrap: break-word;
resize: none;
border: none;
user-select: none;
contain: layout style paint;
/* N.B. This property, while discouraged ("intended for Document Type Definition (DTD) designers") is necessary for ensuring correct mixed RTL/LTR behavior when exporting SVGs. */
unicode-bidi: plaintext;
-webkit-user-select: none;
}
.tl-text-input,
.tl-text-content {
position: absolute;
inset: 0px;
height: 100%;
width: 100%;
min-width: 1px;
min-height: 1px;
outline: none;
}
.tl-text-content__wrapper {
position: relative;
width: fit-content;
height: fit-content;
display: flex;
align-items: center;
justify-content: center;
pointer-events: none;
min-height: auto;
}
.tl-text-content {
overflow: visible;
pointer-events: none;
}
.tl-text-input {
resize: none;
user-select: all;
-webkit-user-select: text;
cursor: var(--tl-cursor-text);
}
.tl-text-input:not(.tl-rich-text) {
/*
* Note: this `overflow: hidden` is key for scrollbars to not show up
* plaintext/<textarea> editors.
*/
overflow: hidden;
}
/**
* Only when there's actually a highlight to style. ProseMirror hides the native selection whenever
* it holds a NodeSelection — triple-clicking a list's bullet selects the whole list, for one — by
* zeroing the ::selection background and nothing else. Painting the selected-contrast color with
* no highlight behind it leaves the text invisible against the shape, and `inherit` can't undo it:
* highlight pseudo-elements inherit from the ancestor's ::selection, so it just picks the same
* color back up.
*/
.tl-text-input:not(:has(.ProseMirror-hideselection))::selection {
background: var(--tl-color-selected);
color: var(--tl-color-selected-contrast);
text-shadow: none;
}
/* Text label */
.tl-text-label {
display: flex;
justify-content: center;
align-items: center;
color: var(--tl-color-text);
line-height: inherit;
position: absolute;
inset: 0px;
height: 100%;
width: 100%;
}
.tl-text-label[data-hastext='false'][data-isediting='false'] > .tl-text-label__inner {
width: 40px;
height: 40px;
}
.tl-text-label[data-hastext='true'][data-isediting='false'] .tl-text-content {
pointer-events: all;
}
.tl-text-label__inner > .tl-text-input.tl-rich-text {
display: none;
position: static;
}
.tl-text-wrapper[data-isediting='false'] .tl-text-input {
opacity: 0;
cursor: var(--tl-cursor-default);
}
.tl-rich-text[data-is-ready-for-editing='true'],
.tl-text-wrapper[data-is-ready-for-editing='true'] .tl-text-input {
cursor: var(--tl-cursor-text);
}
.tl-text-label[data-textwrap='true'] > .tl-text-label__inner {
max-width: 100%;
}
.tl-text-label[data-isediting='true'] {
background-color: transparent;
min-height: auto;
}
.tl-text-wrapper .tl-text-content {
pointer-events: all;
z-index: var(--tl-layer-text-content);
}
.tl-text-label__inner > .tl-text-content {
position: relative;
top: 0px;
left: 0px;
padding: inherit;
height: fit-content;
width: fit-content;
border-radius: var(--tl-radius-1);
max-width: 100%;
}
.tl-text-label__inner > .tl-text-input {
position: absolute;
inset: 0px;
height: 100%;
width: 100%;
padding: inherit;
}
.tl-text-wrapper[data-isselected='true'] .tl-text-input {
z-index: var(--tl-layer-text-editor);
pointer-events: all;
}
/* This part of the rule helps preserve the occlusion rules for the shapes so we
* don't click on shapes that are behind other shapes.
* One extra nuance is we don't use this behavior for:
* - arrows which have weird geometry and just gets in the way.
* - draw/line shapes, because it feels restrictive to have them be 'in the way' of clicking on a textfield
* - shapes that are not filled
*/
.tl-canvas:is([data-iseditinganything='true'], [data-isselectinganything='true'])
.tl-shape:not(
[data-shape-type='arrow'],
[data-shape-type='draw'],
[data-shape-type='line'],
[data-shape-type='highlight'],
[data-shape-is-filled='false']
) {
pointer-events: all;
}
.tl-rich-text .ProseMirror {
word-wrap: break-word;
overflow-wrap: break-word;
white-space: pre-wrap;
/**
* Note: ProseMirror disables this in https://github.com/ProseMirror/prosemirror-view/commit/6b3b2205e2f3029cb8e8e86c55a190a22491df31
* However, that was from 8 years ago and the browser caret issue
* it mentions seems to be fixed. So, we're re-enabling it.
* We'll tell ProseMirror maybe to get rid of this on their end.
*
*/
-webkit-font-variant-ligatures: inherit;
font-variant-ligatures: inherit;
font-feature-settings: inherit;
/**
* N.B. This following CSS Rule comes standard with the tiptap editor.
* Combined with the above rule that it supersedes, it allows for
* the auto-linking to work in text. Say, when typing example.com
* this helps it automatically turn that bit of text into a link.
*
* However, specifically, the break-spaces features seems to cause
* rendering differences when going in-and-out of edit mode. For example,
* the statically rendered text 'the rain in spain falls mainly on the plain'
* in a note shape will render differently when going in-and-out of edit mode.
*
* So, this is commented out to help make both the autolinking work (which now
* relies on the white-space: pre-wrap to work and to make the static/edit-mode
* rendering consistent.
* In the future, we might consider just making the static rendering just use
* white-space: break-spaces to make it consistent with the edit mode if need be.
*
* Also, the amount of ink I've spilt in my career writing comments explaining
* white-space in contenteditable is incredible.
*
/* white-space: break-spaces; */
}
.tl-rich-text {
tab-size: var(--tl-tab-size, 2);
}
.tl-rich-text p {
margin: 0;
/* Depending on the extensions, <p> tags can be empty, without a <br />. */
min-height: 1lh;
}
.tl-rich-text ul,
.tl-rich-text ol {
text-align: left;
margin: 0;
padding-left: 1.625ch;
/* Some resets, like Tailwind, nix the list styling. */
list-style: revert;
}
.tl-rich-text ol:has(> li:nth-child(10)) {
padding-left: 2.625ch;
}
.tl-rich-text ol:has(> li:nth-child(100)) {
padding-left: 3.625ch;
}
.tl-rich-text h1,
.tl-rich-text h2,
.tl-rich-text h3,
.tl-rich-text h4,
.tl-rich-text h5,
.tl-rich-text h6 {
margin-top: 5px;
margin-bottom: 10px;
/**
* Headings render at a larger font-size than the body text (via the browser's
* default h1–h6 sizing), so they can't inherit the container's resolved
* whole-pixel line-height — that value is derived from the base font size and
* would cram the taller lines together. Instead, scale line-height with each
* heading's own font-size using tldraw's unitless line-height multiplier, which
* the rich-text render/measure paths expose here. The 1.35 fallback mirrors the
* default theme line-height (see defaultThemes.ts).
*/
line-height: var(--tl-rich-text-heading-line-height, 1.35);
}
.tl-rich-text a {
color: var(--tl-color-primary);
text-decoration: underline;
}
.tl-rich-text[data-is-select-tool-active='false'] a {
cursor: inherit;
}
.tl-rich-text code {
font-family: var(--tl-font-mono);
}
.tl-rich-text mark {
background-color: #fddd00;
color: currentColor;
border-radius: 2px;
}
.tl-theme__light .tl-rich-text mark {
text-shadow: none;
}
.tl-theme__dark .tl-rich-text mark {
background-color: var(--tl-color-text-highlight);
color: currentColor;
text-shadow: none;
}
@supports (color: color(display-p3 1 1 1)) {
@media (color-gamut: p3) {
.tl-container:not(.tl-theme__force-sRGB) .tl-rich-text mark {
background-color: var(--tl-color-text-highlight-p3);
}
}
}
.tl-text-wrapper[data-isediting='true'] .tl-rich-text {
display: block;
}
.tl-text__outline {
text-shadow: var(--tl-text-outline);
}
.tl-text__no-outline {
text-shadow: none;
}
/* --------------------- Loading -------------------- */
.tl-loading {
background-color: var(--tl-color-background);
color: var(--tl-color-text-1);
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: var(--tl-space-2);
font-size: 14px;
font-weight: 500;
opacity: 0;
animation: tl-fade-in 0.2s ease-in-out forwards;
animation-delay: 0.2s;
position: absolute;
inset: 0px;
z-index: var(--tl-layer-canvas-blocker);
}
@keyframes tl-fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.tl-spinner {
animation: tl-spin 1s linear infinite;
}
@keyframes tl-spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* ---------------- Hyperlink Button ---------------- */
.tl-hyperlink-button {
background: none;
margin: 0px;
position: absolute;
top: 0px;
right: 0px;
height: 44px;
width: 44px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 400;
color: var(--tl-color-text-1);
padding: 13px;
cursor: var(--tl-cursor-pointer);
border: none;
outline: none;
pointer-events: all;
z-index: 1;
}
.tl-hyperlink-button::after {
content: '';
z-index: -1;
position: absolute;
right: 6px;
bottom: 6px;
display: block;
width: calc(100% - 12px);
height: calc(100% - 12px);
border-radius: var(--tl-radius-1);
background-color: var(--tl-color-background);
pointer-events: none;
}
.tl-hyperlink-button:focus-visible {
color: var(--tl-color-selected);
}
.tl-hyperlink__icon {
width: 15px;
height: 15px;
background-color: currentColor;
pointer-events: none;
}
.tl-hyperlink-button__hidden {
display: none;
}
/* ----------------- Shape indicator ---------------- */
.tl-shape-indicator {
transform-origin: top left;
fill: none;
stroke-width: calc(1.5px * var(--tl-scale));
contain: size layout;
}
.tl-canvas-overlays {
position: absolute;
inset: 0;
pointer-events: none;
z-index: var(--tl-layer-canvas-overlays);
}
/* ---------------------- Shape --------------------- */
.tl-shape {
position: absolute;
pointer-events: none;
overflow: visible;
transform-origin: top left;
contain: size layout;
}
/* ---------------- Shape Containers ---------------- */
.tl-svg-container {
position: absolute;
inset: 0px;
height: 100%;
width: 100%;
pointer-events: none;
stroke-linecap: round;
stroke-linejoin: round;
transform-origin: top left;
overflow: visible;
}
.tl-html-container {
position: absolute;
inset: 0px;
height: 100%;
width: 100%;
pointer-events: none;
stroke-linecap: round;
stroke-linejoin: round;
/* content-visibility: auto; */
transform-origin: top left;
color: var(--tl-color-text-1);
}
.tl-content-slot {
position: absolute;
inset: 0px;
height: 100%;
width: 100%;
pointer-events: none;
transform-origin: top left;
}
/* -------------------- Group shape ------------------ */
.tl-group {
stroke: var(--tl-color-text);
stroke-width: calc(1px * var(--tl-scale));
opacity: 0.5;
}
/* --------------------- Arrow shape -------------------- */
.tl-shape[data-shape-type='arrow'] .tl-text-label {
position: absolute;
top: -1px;
left: -1px;
width: 2px;
height: 2px;
padding: 0px;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
color: var(--tl-color-text);
}
.tl-shape[data-shape-type='arrow'] .tl-text-label__inner {
border-radius: var(--tl-radius-1);
box-sizing: content-box;
height: max-content;
width: max-content;
}
.tl-shape[data-shape-type='arrow'] .tl-text {
height: max-content;
}
/* ------------------- Bookmark shape ------------------- */
.tl-bookmark__container {
width: 100%;
height: 100%;
position: relative;
border: 1px solid var(--tl-color-panel-contrast);
background-color: var(--tl-color-panel);
border-radius: var(--tl-radius-2);
display: flex;
flex-direction: column;
overflow: hidden;
}
.tl-bookmark__container--safariExport {
border: 1px solid var(--tl-color-divider);
}
.tl-bookmark__image_container {
flex: 1 1 100%;
overflow: hidden;
border-top-left-radius: var(--tl-radius-1);
border-top-right-radius: var(--tl-radius-1);
width: 100%;
height: 100%;
display: flex;
justify-content: flex-end;
align-items: flex-start;
box-shadow: inset 0px 0px 0px 1px var(--tl-color-divider);
}
.tl-bookmark__image_container > .tl-hyperlink-button::after {
background-color: var(--tl-color-panel);
}
.tl-bookmark__placeholder {
width: 100%;
height: 100%;
background-color: var(--tl-color-muted-2);
border-bottom: 1px solid var(--tl-color-muted-2);
}
.tl-bookmark__image {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
border-bottom: 1px solid var(--tl-color-muted-2);
}
.tl-bookmark__copy_container {
background-color: var(--tl-color-muted-0);
padding: var(--tl-space-4);
pointer-events: all;
display: flex;
flex-direction: column;
justify-content: space-between;
flex: 1;
}
.tl-bookmark__copy_container:has(.tl-bookmark__link:only-child) {
justify-content: center;
}
.tl-bookmark__heading,
.tl-bookmark__description,
.tl-bookmark__link {
margin: 0px;
width: 100%;
font-family: inherit;
}
.tl-bookmark__heading {
font-size: 16px;
line-height: 1.6;
font-weight: bold;
padding-bottom: var(--tl-space-2);
overflow: hidden;
max-height: calc((16px * 1.6) * 2);
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-clamp: 2;
text-overflow: ellipsis;
display: -webkit-box;
}
.tl-bookmark__description {
font-size: 12px;
line-height: 1.5;
overflow: hidden;
max-height: calc((12px * 1.5) * 3);
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
line-clamp: 3;
text-overflow: ellipsis;
display: -webkit-box;
color: var(--tl-color-text-1);
margin: var(--tl-space-2) 0px;
}
.tl-bookmark__heading + .tl-bookmark__link,
.tl-bookmark__description + .tl-bookmark__link {
margin-top: var(--tl-space-3);
}
.tl-bookmark__link {
font-size: 12px;
pointer-events: all;
display: flex;
color: var(--tl-color-text-1);
align-items: center;
cursor: var(--tl-cursor-pointer);
width: fit-content;
max-width: 100%;
text-decoration: none;
}
.tl-bookmark__link > span {
flex-shrink: 0px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.tl-bookmark__link > .tl-hyperlink__icon {
margin-right: 8px;
flex-shrink: 0;
}
.tl-bookmark__link > .tl-bookmark__favicon {
margin-right: 8px;
width: 16px;
height: 16px;
flex-shrink: 0;
}
/* -------------- Image and video shape ------------- */
.tl-image,
.tl-video {
object-fit: cover;
background-size: cover;
width: 100%;
height: 100%;
}
.tl-video-container,
.tl-image-container,
.tl-embed-container {
width: 100%;
height: 100%;
pointer-events: all;
/* background-color: var(--tl-color-background); */
display: flex;
justify-content: center;
align-items: center;
}
.tl-image-container {
position: relative;
}
.tl-image {
position: absolute;
inset: 0;
}
.tl-video.tl-video-is-fullscreen {
object-fit: contain;
background-size: contain;
}
/* -------------------- Note shape ------------------- */
.tl-note__container {
position: relative;
width: 100%;
height: 100%;
pointer-events: all;
opacity: 1;
z-index: var(--tl-layer-text-container);
border-radius: 1px;
}
.tl-note__container > .tl-text-label {
color: currentColor;
}
.tl-note__attribution {
position: absolute;
bottom: calc(4px * var(--note-attribution-scale, 1));
right: calc(8px * var(--note-attribution-scale, 1));
font-family: var(--tl-font-sans);
pointer-events: auto;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 60%;
z-index: 1;
}
/* ------------------- Frame shape ------------------- */
.tl-frame__body {
stroke-width: calc(1px * var(--tl-scale));
}
.tl-frame__creating {
stroke: var(--tl-color-selected);
fill: none;
}
.tl-frame-heading {
--tl-frame-padding-x: 6px;
--tl-frame-height: 24px;
--tl-frame-minimum-width: 32px;
--tl-frame-offset-width: 16px;
display: flex;
align-items: center;
position: absolute;
transform-origin: 0% 100%;
overflow: hidden;
max-width: 100%;
min-width: var(--tl-frame-minimum-width);
height: auto;
font-size: 12px;
padding-bottom: 4px;
pointer-events: all;
}
.tl-frame-heading-hit-area {
pointer-events: all;
/* scale from bottom left corner so we can pin it to the top left corner of the frame */
transform-origin: 0% 100%;
display: flex;
height: var(--tl-frame-height);
width: 100%;
align-items: center;
border-radius: var(--tl-radius-1);
}
.tl-frame-label {
pointer-events: all;
overflow: hidden;
text-overflow: ellipsis;
padding: 0px var(--tl-frame-padding-x);
border-radius: var(--tl-radius-1);
position: relative;
font-size: inherit;
white-space: pre;
}
.tl-frame-label__editing {
color: transparent;
white-space: pre;
width: auto;
min-width: var(--tl-frame-minimum-width);
height: 100%;
overflow: visible;
background-color: var(--tl-color-panel);
border-color: var(--tl-color-selected);
box-shadow: inset 0px 0px 0px 1.5px var(--tl-color-selected);
}
.tl-frame-name-input {
position: absolute;
border: none;
background: none;
outline: none;
padding: 0px var(--tl-frame-padding-x);
inset: 0px;
height: 100%;
width: 100%;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
width: 100%;
color: var(--tl-color-text-1);
border-radius: var(--tl-radius-1);
user-select: all;
-webkit-user-select: text;
white-space: pre;
cursor: var(--tl-cursor-text);
}
/* ------------------- Embed Shape ------------------ */
.tl-embed {
border: none;
border-radius: var(--tl-radius-2);
}
/* -------------- Shape error boundary -------------- */
.tl-shape-error-boundary {
width: 100%;
height: 100%;
background-color: var(--tl-color-muted-1);
border-width: calc(1px * var(--tl-scale));
border-color: var(--tl-color-muted-1);
border-style: solid;
border-radius: calc(var(--tl-radius-1) * var(--tl-scale));
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: left;
position: relative;
pointer-events: all;
overflow: hidden;
padding: var(--tl-space-2);
}
.tl-shape-error-boundary::before {
transform: scale(var(--tl-scale));
content: 'Error';
font-size: 12px;
font-family: inherit;
color: var(--tl-color-text-0);
}
/* ----------------- Error boundary ----------------- */
.tl-error-boundary {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: var(--tl-space-4);
background-color: var(--tl-color-background);
color: var(--tl-color-text-1);
position: absolute;
}
.tl-error-boundary__overlay {
position: absolute;
inset: 0px;
height: 100%;
width: 100%;
z-index: var(--tl-layer-error-overlay);
background-color: var(--tl-color-overlay);
}
.tl-error-boundary__content * {
user-select: all;
-webkit-user-select: text;
pointer-events: all;
}
.tl-error-boundary__canvas {
pointer-events: none;
position: absolute;
inset: 0px;
height: 100%;
width: 100%;
z-index: var(--tl-layer-error-canvas);
}
/* some browsers seem to have some weird interactions between stacking contexts
and pointer-events. this ::after pseudo element covers the canvas and prevents
it from receiving any pointer events or affecting the cursor. */
.tl-error-boundary__canvas::after {
content: ' ';
display: block;
position: absolute;
inset: 0px;
height: 100%;
width: 100%;
z-index: var(--tl-layer-error-canvas-after);
pointer-events: all;
}
.tl-error-boundary__content {
width: fit-content;
height: fit-content;
max-width: 100%;
width: 400px;
max-height: 100%;
background-color: var(--tl-color-panel);
padding: 16px;
border-radius: 16px;
box-shadow: var(--tl-shadow-2);
font-size: 14px;
font-weight: 400;
display: flex;
flex-direction: column;
overflow: auto;
z-index: var(--tl-layer-error-content);
gap: 12px;
}
.tl-error-boundary__content__expanded {
width: 600px;
}
.tl-error-boundary__content h2 {
font-size: 16px;
margin: 0px;
font-weight: 500;
}
.tl-error-boundary__content h4 {
border: 1px solid var(--tl-color-low-border);
margin: -6px 0 0 0;
padding: var(--tl-space-5);
border-radius: var(--tl-radius-2);
font-weight: normal;
}
.tl-error-boundary__content p {
line-height: 1.5;
margin: 0px;
}
.tl-error-boundary__content pre {
background-color: var(--tl-color-muted-2);
margin-top: 0;
padding: var(--tl-space-5);
border-radius: var(--tl-radius-2);
overflow: auto;
font-size: 12px;
max-height: 320px;
}
.tl-error-boundary__content button {
background: none;
border: none;
font-family: inherit;
font-size: 14px;
font-weight: 500;
padding: var(--tl-space-4);
border-radius: var(--tl-radius-3);
cursor: var(--tl-cursor-pointer);
color: inherit;
background-color: transparent;
}
.tl-error-boundary__content a {
color: var(--tl-color-selected);
font-weight: 500;
text-decoration: none;
}
.tl-error-boundary__content__error {
position: relative;
margin: -6px 0 0 0;
}
.tl-error-boundary__content__error button {
position: absolute;
top: var(--tl-space-2);
right: var(--tl-space-2);
font-size: 12px;
padding: var(--tl-space-2) var(--tl-space-3);
background-color: var(--tl-color-panel);
border-radius: var(--tl-radius-1);
}
.tl-error-boundary__content__actions {
display: flex;
justify-content: space-between;
gap: var(--tl-space-4);
margin: 0px;
margin-left: -4px;
}
.tl-error-boundary__content__actions__group {
display: flex;
gap: var(--tl-space-4);
}
.tl-error-boundary__content .tl-error-boundary__reset {
color: var(--tl-color-danger);
}
.tl-error-boundary__content .tl-error-boundary__refresh {
background-color: var(--tl-color-primary);
color: var(--tl-color-selected-contrast);
}
.tl-container__focused:not(.tl-container__no-focus-ring)
.tlui-button.tl-error-boundary__refresh:focus-visible {
border-radius: 8px;
outline-offset: 0;
}
/* ---------------- Hit test blocker ---------------- */
.tl-hit-test-blocker {
position: absolute;
z-index: var(--tl-layer-canvas-blocker);
inset: 0px;
width: 100%;
height: 100%;
pointer-events: all;
}
.tl-hit-test-blocker__hidden {
display: none;
}
/* --------------------- Hovers --------------------- */
@media (hover: hover) {
.tl-handle__create:hover {
opacity: 1;
}
.tl-handle__bg:hover {
cursor: var(--tl-cursor-grab);
fill: var(--tl-color-selection-fill);
}
.tl-bookmark__link:hover {
color: var(--tl-color-selected);
}
.tl-hyperlink-button:hover {
color: var(--tl-color-selected);
}
.tl-error-boundary__content button:hover {
background-color: var(--tl-color-low);
}
.tl-error-boundary__content a:hover {
color: var(--tl-color-text-1);
}
.tl-error-boundary__content .tl-error-boundary__refresh:hover {
background-color: var(--tl-color-primary);
opacity: 0.9;
}
/* These three rules help preserve clicking into specific points in text areas *while*
* already in edit mode when jumping from shape to shape. */
.tl-canvas[data-iseditinganything='true'] .tl-text-wrapper:hover .tl-text-input {
z-index: var(--tl-layer-text-editor);
pointer-events: all;
}
}