feat: squircle corners

Layer continuous-curvature (squircle) corners on top of the existing
border-radius on card/lane/button/panel/input surfaces via a
`--corner: squircle` token and `corner-shape: var(--corner)`.

corner-shape is Chromium-only as of mid-2026 (Safari/WebKit & Firefox
ignore it and keep the plain border-radius arc), and it requires a
non-zero radius to render — so this is pure progressive enhancement
with zero visual regression. Pills (border-radius: 999px) and the
full-screen 0-radius editor are deliberately left untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
chodaict 2026-06-11 16:22:26 +09:00
parent 2bab893e80
commit 15813173ab

View file

@ -1,4 +1,10 @@
/* tugtile — markdown kanban (prototype, read-only renderer) */
/* Squircle corners: continuous-curvature corners layered on top of the existing
border-radius. corner-shape is Chromium-only as of mid-2026 (Safari/WebKit & Firefox
ignore it and keep the plain border-radius arc), so this is pure progressive
enhancement with zero visual regression. corner-shape needs a non-zero radius to do
anything and is not inherited but the custom property is, so we route through a token. */
:root { --corner: squircle; }
.tugtile {
height: 100%;
padding: 0;
@ -44,7 +50,7 @@ body.is-phone .workspace-leaf-content[data-type="tugtile-board"] .view-content {
.tugtile-brand {
display: inline-flex; align-items: center; gap: 5px;
color: var(--text-faint); font-weight: var(--font-normal);
cursor: pointer; border-radius: var(--radius-s); padding: 2px 6px;
cursor: pointer; border-radius: var(--radius-s); corner-shape: var(--corner); padding: 2px 6px;
}
.tugtile-brand:hover { background: var(--background-modifier-hover); color: var(--text-muted); }
.tugtile-lock-icon { display: inline-flex; }
@ -77,7 +83,7 @@ body.is-phone .workspace-leaf-content[data-type="tugtile-board"] .view-content {
display: flex;
flex-direction: column;
background: var(--background-secondary);
border-radius: var(--radius-m);
border-radius: var(--radius-m); corner-shape: var(--corner);
padding: 8px;
overflow: hidden; /* Cleanly clips content into the changing lane width during collapse/expand (dragging uses a clone on body and is unaffected) */
--tg-d1: 0.26s; /* Stage 1: lane narrows + horizontal title tucks into the chevron (collapse) / widens + title grows back (expand) */
@ -127,7 +133,7 @@ body.is-phone .workspace-leaf-content[data-type="tugtile-board"] .view-content {
position: relative;
background: var(--background-primary);
border: 1px solid var(--background-modifier-border);
border-radius: var(--radius-m);
border-radius: var(--radius-m); corner-shape: var(--corner);
padding: 8px;
cursor: grab;
}
@ -167,7 +173,7 @@ body.is-phone .workspace-leaf-content[data-type="tugtile-board"] .view-content {
padding: 0 0.4em;
background: var(--interactive-accent);
color: var(--text-on-accent);
border-radius: var(--radius-s);
border-radius: var(--radius-s); corner-shape: var(--corner);
font-weight: 700;
line-height: 1.25;
}
@ -212,7 +218,7 @@ body.is-phone .workspace-leaf-content[data-type="tugtile-board"] .view-content {
z-index: 9999;
background: var(--background-primary);
border: 1px solid var(--background-modifier-border);
border-radius: var(--radius-m);
border-radius: var(--radius-m); corner-shape: var(--corner);
box-shadow: var(--shadow-l);
padding: 8px;
user-select: none;
@ -241,7 +247,7 @@ body.is-phone .workspace-leaf-content[data-type="tugtile-board"] .view-content {
.tugtile__popup-w { opacity: 0.5; font-size: 0.8em; }
.tugtile__popup-d {
cursor: pointer;
border-radius: var(--radius-s);
border-radius: var(--radius-s); corner-shape: var(--corner);
padding: 3px 0;
line-height: 1.4;
}
@ -255,7 +261,7 @@ body.is-phone .workspace-leaf-content[data-type="tugtile-board"] .view-content {
.tugtile__popup-t {
cursor: pointer;
padding: 4px 16px;
border-radius: var(--radius-s);
border-radius: var(--radius-s); corner-shape: var(--corner);
}
.tugtile__popup-t:hover { background: var(--background-modifier-hover); }
/* Tag chips at the bottom of the card (when move-tags-to-card-footer is enabled) */
@ -305,7 +311,7 @@ body.is-phone .workspace-leaf-content[data-type="tugtile-board"] .view-content {
text-align: left;
background: transparent;
border: 1px dashed var(--background-modifier-border);
border-radius: var(--radius-m);
border-radius: var(--radius-m); corner-shape: var(--corner);
color: var(--text-muted);
padding: 8px; /* Match card padding and the add-lane button (consistent 8px rhythm); left-aligned "+" lines up with the card number chip */
cursor: pointer;
@ -318,13 +324,13 @@ body.is-phone .workspace-leaf-content[data-type="tugtile-board"] .view-content {
width: 100%;
min-height: 4em;
resize: vertical;
border-radius: var(--radius-m);
border-radius: var(--radius-m); corner-shape: var(--corner);
}
.tugtile__add-ok {
background: var(--interactive-accent);
color: var(--text-on-accent);
border: none;
border-radius: var(--radius-s);
border-radius: var(--radius-s); corner-shape: var(--corner);
padding: 4px 12px;
cursor: pointer;
}
@ -438,7 +444,7 @@ body.is-phone .tugtile-prompt-modal { margin-top: calc(env(safe-area-inset-top)
box-sizing: border-box; height: 40px; padding: 0 12px;
background: var(--background-modifier-form-field);
border: 1px solid var(--background-modifier-border);
border-radius: var(--radius-m);
border-radius: var(--radius-m); corner-shape: var(--corner);
overflow: hidden; /* Clip the input to the rounded box so it can never poke out of the corners */
}
.tugtile-prompt-field:focus-within { border-color: var(--interactive-accent); }
@ -497,7 +503,7 @@ input.tugtile-prompt-input:active {
-webkit-appearance: none; appearance: none;
position: relative;
width: 40px; height: 40px;
border: none; border-radius: var(--radius-m);
border: none; border-radius: var(--radius-m); corner-shape: var(--corner);
background: transparent; color: var(--text-muted);
cursor: pointer;
}
@ -542,7 +548,7 @@ body.is-phone .tugtile-ed-bar { padding-top: 6px; padding-bottom: 4px; }
}
.tugtile-ed-find-i {
flex: 1; min-width: 80px;
font-size: 16px; padding: 5px 8px; border-radius: var(--radius-s); /* 16px avoids iOS focus-zoom */
font-size: 16px; padding: 5px 8px; border-radius: var(--radius-s); corner-shape: var(--corner); /* 16px avoids iOS focus-zoom */
}
.tugtile-ed-find-n { flex: 0 0 auto; color: var(--text-muted); font-size: 0.85em; min-width: 1.6em; text-align: center; }
/* .tugtile-ed-find-b inherits everything from .tugtile-iconbtn */
@ -609,7 +615,7 @@ body.is-phone .tugtile-ed-bar { padding-top: 6px; padding-bottom: 4px; }
.marktile-toc-item--ghost { opacity: 0.4; background: var(--background-modifier-hover); } /* the gap left behind */
.marktile-toc-item--chosen { box-shadow: inset 0 0 0 2px var(--interactive-accent); } /* the picked row */
.marktile-toc-item--drag { /* the row following the finger (re-parented to <body> by fallbackOnBody) */
opacity: 0.97; background: var(--background-secondary); border-radius: 6px;
opacity: 0.97; background: var(--background-secondary); border-radius: 6px; corner-shape: var(--corner);
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.4); cursor: grabbing;
rotate: 3deg; scale: 1.03; /* "picked up" tilt — standalone props (NOT transform) so Sortable's drag translation isn't overwritten */
}
@ -658,7 +664,7 @@ body.is-phone .tugtile-ed-rich { padding-bottom: 55vh; }
width: 100%;
min-height: 4em;
resize: vertical;
border-radius: var(--radius-s);
border-radius: var(--radius-s); corner-shape: var(--corner);
}
/* Lane header container */
.tugtile__lane-title {
@ -679,7 +685,7 @@ body.is-phone .tugtile-ed-rich { padding-bottom: 55vh; }
.tugtile__lane-rename {
flex: 1;
font-weight: 700;
border-radius: var(--radius-s);
border-radius: var(--radius-s); corner-shape: var(--corner);
}
/* Responsive board (opt-in, default off): on a narrow pane the horizontal lanes reflow into a single full-width vertical stack — the behaviour of the retired List view, now automatic via a container query. Drag-and-drop/editing logic is shared with the board view. */
.tugtile--rwd { container-type: inline-size; container-name: tugtileboard; }
@ -698,7 +704,7 @@ body.is-phone .tugtile-ed-rich { padding-bottom: 55vh; }
/* Centered header view-cycle control: "<icon> <name>" — click cycles board → table → markdown. Same padding as the lock button so the "·" separator sits symmetrically between them. */
.tugtile-viewcycle {
display: inline-flex; align-items: center; gap: 5px;
cursor: pointer; border-radius: var(--radius-s);
cursor: pointer; border-radius: var(--radius-s); corner-shape: var(--corner);
padding: 2px 6px;
}
.tugtile-viewcycle:hover { background: var(--background-modifier-hover); }
@ -749,7 +755,7 @@ body.is-phone .tugtile-ed-rich { padding-bottom: 55vh; }
margin: 0 12px 8px;
padding: 12px;
border: 2px dashed var(--background-modifier-border);
border-radius: var(--radius-m);
border-radius: var(--radius-m); corner-shape: var(--corner);
background: var(--background-secondary);
color: var(--text-muted);
font-weight: 600;
@ -762,7 +768,7 @@ body.is-phone .tugtile-ed-rich { padding-bottom: 55vh; }
flex: 0 0 auto;
width: 1.6em;
height: 1.6em;
border-radius: var(--radius-s);
border-radius: var(--radius-s); corner-shape: var(--corner);
/* Opaque (translucent hover tint composited over the lane bg) so the vertical title retracting INTO the
chevron during collapse/expand is fully masked a see-through button would leak that text. */
background: linear-gradient(var(--background-modifier-hover), var(--background-modifier-hover)), var(--background-secondary);
@ -862,7 +868,7 @@ body.is-phone .tugtile-ed-rich { padding-bottom: 55vh; }
gap: 8px;
padding: 8px;
border: 1px solid var(--background-modifier-border);
border-radius: var(--radius-m);
border-radius: var(--radius-m); corner-shape: var(--corner);
}
.tugtile-archive-body {
flex: 1;
@ -886,7 +892,7 @@ body.is-phone .tugtile-ed-rich { padding-bottom: 55vh; }
text-align: left; /* Match the add-card button (consistent left-aligned "+ label") */
background: transparent;
border: 1px dashed var(--background-modifier-border);
border-radius: var(--radius-m);
border-radius: var(--radius-m); corner-shape: var(--corner);
color: var(--text-muted);
padding: 8px;
cursor: pointer;