@use 'sass:color'; // Colour palette $primary-blue: #2451a6; $light-blue: #85bff7; $green: #12d197; $text-primary: #23272f; $text-secondary: #5a6272; $border-grey: #d1d5db; $code-bg: #61769a; $code-text: #e2e8f0; $white: #fff; $light-bg: #f8fafc; $gradient-end: #e0e7ef; // Function to create selection colour with opacity @function selection-colour($colour, $opacity: 0.3) { @return rgba($colour, $opacity); } @function caret-colour($colour, $amount: 20%) { @return color.adjust($colour, $lightness: -$amount); } * { box-sizing: border-box; margin: 0; user-select: none; } html, body { height: 100%; } body { font-family: 'Segoe UI', Arial, sans-serif; color: $text-primary; } .scroll-container { height: 100vh; height: 100dvh; overflow-y: auto; overflow-x: hidden; } .background { background: linear-gradient(135deg, $light-bg 0%, $gradient-end 100%); position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: -1; } .page-wrapper { display: flex; flex-direction: column; justify-content: space-between; min-height: 100%; max-width: 1000px; margin: 0 auto; } header { padding: 32px 32px 0 32px; } header > h1 { font-size: 2.5rem; font-weight: 700; color: $primary-blue; margin-bottom: 24px; text-align: center; } h1, code, p, p * { user-select: text; } code { background: $code-bg; color: $code-text; padding: 2px 6px; border-radius: 4px; font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', 'Consolas', monospace; font-size: 0.875em; font-weight: 500; } header > p { color: $text-secondary; font-size: 1.1rem; margin-bottom: 0; } header > p:not(:first-of-type) { margin-top: 16px; } main { display: grid; grid-template-rows: min-content min-content min-content; grid-template-columns: 1fr 1fr; gap: 20px; justify-items: center; align-items: center; padding: 32px; } .tokenizer-selector { grid-column: 1 / -1; grid-row: 1; width: 100%; margin-bottom: 8px; } .radio-group { display: flex; gap: 16px; justify-content: center; flex-wrap: wrap; } .radio-option { display: flex; align-items: center; gap: 12px; padding: 16px 20px; background: $white; border-radius: 12px; box-shadow: 0 2px 8px selection-colour($primary-blue, 0.08); cursor: pointer; transition: all 0.2s ease; border: 2px solid transparent; min-width: 180px; position: relative; } .radio-option:hover { box-shadow: 0 4px 16px selection-colour($primary-blue, 0.12); transform: translateY(-2px); } .radio-option:has(input:checked) { background: $gradient-end; border-color: $primary-blue; box-shadow: 0 4px 16px selection-colour($primary-blue, 0.16); } .radio-option input[type='radio'] { position: absolute; opacity: 0; pointer-events: none; } .radio-custom { width: 20px; height: 20px; border: 2px solid $border-grey; border-radius: 50%; position: relative; transition: all 0.2s ease; flex-shrink: 0; } .radio-option:has(input:checked) .radio-custom { border-color: $primary-blue; background: $primary-blue; } .radio-custom::after { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0); width: 8px; height: 8px; border-radius: 50%; background: white; transition: transform 0.2s ease; } .radio-option:has(input:checked) .radio-custom::after { transform: translate(-50%, -50%) scale(1); } .radio-content { display: flex; flex-direction: column; gap: 2px; } .radio-label { font-weight: 600; color: $primary-blue; font-size: 0.95rem; } .radio-description { font-size: 0.8rem; color: $text-primary; line-height: 1.2; } .diamond-parent { grid-column: 1 / -1; grid-row: 2; } .diamond-left { grid-column: 1; grid-row: 3; } .diamond-right { grid-column: 2; grid-row: 3; } .diamond-result { grid-column: 1 / -1; grid-row: 4; } .diamond-result label { display: flex; align-items: center; } .diamond-result svg { width: 20px; height: 20px; margin-left: 8px; } .text-area-card { width: 100%; height: 100%; background: $white; border-radius: 10px; box-shadow: 0 2px 12px 0 selection-colour($primary-blue, 0.06); padding: 18px 20px 16px 20px; margin-bottom: 0; } label { display: inline-block; margin-bottom: 8px; font-weight: 600; color: $primary-blue; cursor: help; } .box { width: 1ch; height: 1ch; border-radius: 50%; margin-left: 6px; display: inline-block; transform: scale(1.5); } textarea { width: 100%; border: none; font-size: 1rem; font-family: inherit; color: $text-primary; box-sizing: border-box; resize: none; outline: none; margin-bottom: 0; field-sizing: content; /* Doesn't work in Safari yet */ } #merged { width: 100%; user-select: text; > * { position: relative; white-space: pre-wrap; } } .Unchanged { user-select: text; } .Left, .AddedFromLeft, .RemovedFromLeft { user-select: text; background: $green; } .selection-left::after, .selection-right::after { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; } .selection-left::after { background: selection-colour($green); } .selection-right::after { background: selection-colour($light-blue); } .Right, .AddedFromRight, .RemovedFromRight { user-select: text; background: $light-blue; } .RemovedFromLeft, .RemovedFromRight { user-select: none; text-decoration: line-through; } // Selection caret styles $CARET_WIDTH: 2; $DOT_RADIUS: 4; .selection-caret { position: relative; z-index: 1000; &.selection-caret-left { background: caret-colour($green); } &.selection-caret-right { background: caret-colour($light-blue); } > * { position: absolute; background-color: inherit; } > .stick { left: 0; top: 0; transform: translateX(-50%); width: #{$CARET_WIDTH}px; height: 100%; display: block; border-radius: calc(#{$CARET_WIDTH} / 2 * 1px); animation: blink-stick 1s steps(1) infinite; } > .dot { border-radius: 50%; width: #{$DOT_RADIUS * 2}px; height: #{$DOT_RADIUS * 2}px; top: -#{$DOT_RADIUS}px; left: -#{$DOT_RADIUS}px; transition: opacity 0.3s ease-in-out; transform-origin: bottom center; box-sizing: border-box; &::before { content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 30px; height: 30px; border-radius: 50%; } } &:hover > .dot { opacity: 0; } > .info { top: -1.3em; left: calc(-#{$CARET_WIDTH} / 2 * 1px); font-size: 0.9em; user-select: none; color: white; padding: 0 2px; transition: opacity 0.3s ease-in-out; opacity: 0; white-space: nowrap; border-radius: 3px 3px 3px 0; } &:hover > .info { opacity: 1; } } @keyframes blink-stick { 0%, 100% { opacity: 1; } 50% { opacity: 0; } } @media (max-width: 900px) { header { padding: 32px 18px 0 18px; } header > h1 { margin-bottom: 18px; } header > p { font-size: 1rem; } main { padding: 18px; } } @media (max-width: 768px) { main { grid-template-columns: 1fr; grid-template-rows: auto auto auto auto auto; } .tokenizer-selector { grid-column: 1; grid-row: 1; } .diamond-parent { grid-column: 1; grid-row: 2; } .diamond-left { grid-column: 1; grid-row: 3; } .diamond-right { grid-column: 1; grid-row: 4; } .radio-group { flex-direction: column; gap: 12px; } .radio-option { min-width: unset; width: 100%; } .diamond-result { grid-column: 1; grid-row: 5; } } footer { padding: 16px; width: 100%; position: relative; display: flex; justify-content: center; align-items: center; color: $text-secondary; } .github-link > svg { position: absolute; color: $text-secondary; top: 50%; right: 36px; transform: translateY(-50%); width: 32px; height: 32px; transition: transform 0.2s; } .github-link > svg:hover { cursor: pointer; transform: translateY(-50%) scale(1.15); }