Files
kokkoja-rel/client/kokkoja.css
T

539 lines
13 KiB
CSS
Raw Normal View History

2026-10-06 15:58:02 +02:00
:root {
--ink: #1c1c1e;
--muted: #6b6b70;
--line: #d4d4d8;
--panel: #f6f6f7;
--desk: #e4e4e7;
--accent: #1f4fd8;
--text_frame: #e53935; /* A text rectangle's frame: the palette's red. */
2026-10-06 15:58:02 +02:00
font-family: system-ui, sans-serif;
font-size: 15px;
color: var(--ink);
}
* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
[hidden] { display: none !important; }
button, input { font: inherit; color: inherit; }
/* A drag across the controls selects nothing: their text is not for
copying (Andy, 2026-10-07). Fields stay selectable. Safari on iOS
and iPadOS knows only the prefixed property (MDN's compatibility
data, 2026-10-10); without it the Pencil's first movement sometimes
selected the save status on Andy's iPad. */
button, select, label, .toolbar, .panel h2, #participants, .chooser header
{ -webkit-user-select: none; user-select: none; }
2026-10-06 15:58:02 +02:00
button {
padding: 0.35rem 0.8rem;
border: 1px solid var(--line);
border-radius: 6px;
background: white;
cursor: pointer;
}
button:hover { border-color: var(--muted); }
button[aria-pressed="true"] {
border-color: var(--accent);
box-shadow: inset 0 0 0 1px var(--accent);
}
input[type="text"], select.notebook_pick {
2026-10-06 15:58:02 +02:00
width: 100%;
padding: 0.4rem 0.5rem;
border: 1px solid var(--line);
border-radius: 6px;
background: white;
font: inherit;
color: inherit;
2026-10-06 15:58:02 +02:00
}
h2 {
margin: 1.4rem 0 0.4rem;
font-size: 0.8rem;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--muted);
}
/* Start screen */
#start {
max-width: 28rem;
margin: 0 auto;
padding: 3rem 1.5rem;
}
#start h1 { margin: 0 0 1.5rem; font-size: 1.6rem; }
#start label { display: block; margin: 1rem 0 0.3rem; }
#start section { margin-top: 1.5rem; }
#start section p { margin: 0 0 0.6rem; color: var(--muted); }
#start section button { margin-top: 0.6rem; }
.message { min-height: 1.4em; margin-top: 1.5rem; color: #b42318; }
.note { margin: 0.3rem 0 0; font-size: 0.85rem; color: var(--muted); overflow-wrap: anywhere; }
.note.problem { color: #b42318; }
.file { margin: 0; overflow-wrap: anywhere; }
/* Session */
#session {
display: flex;
flex-direction: column;
height: 100%;
}
/* One row, holding everything (Andy's teacher, 2026-10-08: the whole
width of the window belongs to the page); it wraps only when the window
is too narrow for it. */
2026-10-06 15:58:02 +02:00
.toolbar {
display: flex;
flex-wrap: wrap;
2026-10-06 15:58:02 +02:00
align-items: center;
gap: 0.5rem 0.55rem;
padding: 0.4rem 0.5rem;
2026-10-06 15:58:02 +02:00
border-bottom: 1px solid var(--line);
background: var(--panel);
}
2026-10-11 13:17:22 +02:00
/* Three groups (Andy, 2026-10-11): the drawing tools with their settings
and Undo on the left; the page and the view in the middle, centred
between the other two; the session's buttons flush right. The
drawing group keeps the width of its widest state (main.js sets its
min-width by measuring), so that the middle group stays put when the
tool changes. */
.drawing, .settings { display: flex; align-items: center; gap: 0.5rem 0.55rem; }
/* Twice the gap before Eraser, Hide and Undo, so that with the pen the
widest line and the Eraser read as two groups (Andy, 2026-10-11). */
.drawing .after_settings { margin-left: 0.55rem; }
.toolbar .page_view { margin-left: auto; margin-right: auto; }
/* When the window is too narrow for one row, the tools are centred
instead of standing at the two ends (Andy, 2026-10-09; main.js sets
the class by measuring). */
.toolbar.wrapped { justify-content: center; }
2026-10-11 13:17:22 +02:00
.toolbar.wrapped .page_view { margin-left: 0; margin-right: 0; }
.toolbar.wrapped .toolbar_right { margin-left: 0; justify-content: center; }
2026-10-11 13:17:22 +02:00
/* 9rem wide until 2026-10-11: room for Undo. The buttons' height, else
this select, 36 px tall by its own padding, sets the row's height and
the buttons' trimming gains nothing (measured 2026-10-11). */
.toolbar .notebook_pick, .toolbar #session_notebook_name {
width: 7.2rem;
height: calc(2rem - 2px);
padding-top: 0;
padding-bottom: 0;
box-sizing: border-box;
}
.toolbar .toggle { display: flex; align-items: center; gap: 0.3rem; cursor: pointer; }
.toolbar .toggle input { margin: 0; }
2026-10-06 15:58:02 +02:00
.group { display: flex; align-items: center; gap: 0.35rem; }
.swatch {
width: 1.5rem;
height: 1.5rem;
padding: 3px;
border-radius: 50%;
background: var(--swatch);
background-clip: content-box;
}
/* The same height as the buttons, so the toolbar does not change height;
narrow enough that a host's toolbar fits a 1920-pixel screen in one
2026-10-11 13:17:22 +02:00
row (measured 2026-10-09: about 1750 pixels with these settings).
Since 2026-10-11 two pixels less in height and on each side than
2rem and 0.6rem, for room (Andy, in two steps of a pixel). */
2026-10-06 15:58:02 +02:00
.toolbar button:not(.swatch), #text_size, #text_font {
box-sizing: border-box;
2026-10-11 13:17:22 +02:00
height: calc(2rem - 2px);
2026-10-06 15:58:02 +02:00
padding-top: 0;
padding-bottom: 0;
}
2026-10-11 13:17:22 +02:00
.toolbar button:not(.swatch) { padding-left: calc(0.6rem - 2px); padding-right: calc(0.6rem - 2px); }
2026-10-06 15:58:02 +02:00
#text_size, #text_font {
margin: 0;
padding-left: 0.4rem;
padding-right: 0.4rem;
border: 1px solid var(--line);
border-radius: 6px;
background: white;
font: inherit;
}
#text_size { width: 3.6rem; }
#text_font { padding-right: 0.3rem; }
/* The palette that "+" opens: no system dialog, which crashes Firefox on
Linux (Hollis, 2026-10-04). */
.palette {
position: absolute;
z-index: 5;
display: grid;
grid-template-columns: repeat(8, 1.5rem);
gap: 0.3rem;
padding: 0.5rem;
border: 1px solid var(--line);
border-radius: 8px;
background: white;
box-shadow: 0 4px 16px rgb(0 0 0 / 0.2);
}
.palette .swatch { width: 1.5rem; height: 1.5rem; }
/* A colour already in the toolbar leaves its place in the grid empty. */
.palette .swatch.missing { visibility: hidden; }
2026-10-06 15:58:02 +02:00
.swatch.more {
--swatch: white;
font-size: 1rem;
line-height: 1;
color: var(--muted);
}
.width_choice {
display: flex;
align-items: center;
justify-content: center;
width: 2.4rem;
height: 1.9rem;
padding: 0;
}
.width_choice span {
display: block;
width: 1.4rem;
border-radius: 99px;
background: var(--ink);
}
/* The page, the notebook and the session: flush right, the page number
and what is going on at the very end (Andy, 2026-10-08). */
2026-10-06 15:58:02 +02:00
.toolbar_right {
display: flex;
flex-wrap: wrap;
2026-10-06 15:58:02 +02:00
align-items: center;
gap: 0.5rem 0.55rem;
2026-10-11 13:17:22 +02:00
margin-left: 0; /* auto until 2026-10-11; the middle group's margins push it right now. */
min-width: 0;
}
/* The notice line between the toolbar and the page: nothing, and no
room, while all is well; a problem in red while it lasts; a
confirmation for a few seconds (Andy, 2026-10-10: the toolbar's
"Page 3 Connected Saved at …" was noise, and the room is needed for
one row). */
.notice {
padding: 0.3rem 1rem;
border-bottom: 1px solid var(--line);
background: var(--panel);
text-align: center;
font-size: 0.9rem;
color: var(--muted);
2026-10-06 15:58:02 +02:00
}
.notice.problem { color: #b42318; }
2026-10-06 15:58:02 +02:00
/* The quiet facts in the Session window: the page, the connection, the
last save. */
.session_state span { margin-right: 1rem; white-space: nowrap; }
.session_state .problem { color: #b42318; }
2026-10-06 15:58:02 +02:00
.workspace {
display: flex;
flex: 1;
min-height: 0;
}
.desk {
flex: 1;
min-width: 0;
overflow: auto;
padding: 0.5rem;
2026-10-06 15:58:02 +02:00
background: var(--desk);
}
/* The cue around an image being moved or scaled by hand: green, with a
square at the corner being dragged. */
.image_grip {
position: absolute;
z-index: 3;
box-sizing: border-box;
border: 2px solid #2e7d32;
pointer-events: none;
}
.image_grip.corner::after {
content: "";
position: absolute;
left: var(--corner-x);
top: var(--corner-y);
width: 12px;
height: 12px;
transform: translate(-50%, -50%);
background: #2e7d32;
}
2026-10-06 15:58:02 +02:00
.page {
position: relative;
margin: 0 auto;
background: white;
box-shadow: 0 1px 4px rgb(0 0 0 / 0.25);
touch-action: none;
-webkit-user-select: none; /* Safari on iOS: see the controls rule. */
2026-10-06 15:58:02 +02:00
user-select: none;
-webkit-touch-callout: none; /* No callout from a long press of the Pencil. */
2026-10-06 15:58:02 +02:00
cursor: crosshair;
}
.page canvas, .page_image {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
/* Text being edited */
.text_field {
position: absolute;
z-index: 2;
box-sizing: content-box;
margin: 0;
padding: 0;
border: none;
border-radius: 0;
background: transparent;
resize: none;
overflow: hidden;
outline: none;
}
/* A rectangle being dragged open, for text or for Hide. */
.rect_preview {
2026-10-06 15:58:02 +02:00
position: absolute;
z-index: 3;
box-sizing: border-box;
border: 2px dotted #ababab;
pointer-events: none;
2026-10-06 15:58:02 +02:00
}
/* The field of a text rectangle shows its frame and white ground itself,
since the renderer leaves the block out while it is edited. */
.text_field.rect {
background: white;
outline-style: solid;
outline-color: var(--text_frame);
2026-10-06 15:58:02 +02:00
}
/* Free text's corner mark while it is edited: an L at its top-left corner. */
.text_mark {
2026-10-06 15:58:02 +02:00
position: absolute;
z-index: 3;
box-sizing: border-box;
border-style: solid none none solid;
border-color: var(--text_frame);
2026-10-06 15:58:02 +02:00
pointer-events: none;
}
/* The Session dialog: who is here, and the invitation. */
2026-10-06 15:58:02 +02:00
/* fit-content, not auto: a modal dialog has its top and bottom pinned by
the browser's own style, so an auto height filled the window up to the
maximum (seen 2026-10-10: 1100 px of dialog around 350 px of content). */
.chooser.session { width: min(32rem, 90vw); height: fit-content; max-height: 85vh; }
.session_body h3 { margin: 1rem 0 0.4rem; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.session_body ul { margin: 0; padding: 0; list-style: none; }
2026-10-06 15:58:02 +02:00
.session_body li {
2026-10-06 15:58:02 +02:00
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.2rem 0;
}
.session_body li.absent { color: var(--muted); }
.session_body li label { flex: 1; }
.session_body li .role { font-size: 0.8rem; color: var(--muted); }
.session_body li .allow_line { order: 1; display: flex; align-items: center; gap: 0.3rem; font-size: 0.8rem; color: var(--muted); cursor: pointer; }
.session_body li .allow_line input { margin: 0; }
.invitation_line { display: flex; gap: 0.5rem; align-items: center; }
.invitation_line input { flex: 1; min-width: 0; }
/* The invitation as a QR code, for the camera of a phone or a tablet. */
.invitation_code { width: min(13rem, 60vw); margin: 0.75rem auto 0; }
.invitation_code svg { display: block; width: 100%; height: auto; }
/* The log, the latest entry at the bottom and in view, selectable. */
.log_line { display: flex; gap: 0.5rem; align-items: flex-start; }
.event_log {
flex: 1;
min-width: 0;
margin: 0;
max-height: 10rem;
overflow: auto;
padding: 0.3rem 0.4rem;
border: 1px solid var(--line);
border-radius: 6px;
font-size: 0.7rem;
line-height: 1.35;
color: var(--muted);
white-space: pre;
-webkit-user-select: text;
user-select: text;
}
2026-10-06 15:58:02 +02:00
/* The notebook chooser */
.chooser {
width: min(56rem, 90vw);
height: min(36rem, 85vh);
padding: 1rem 1.25rem;
border: 1px solid var(--line);
border-radius: 10px;
box-shadow: 0 8px 30px rgb(0 0 0 / 0.25);
}
.chooser::backdrop { background: rgb(0 0 0 / 0.3); }
.chooser header { display: flex; align-items: center; }
.chooser header h2 { flex: 1; margin: 0; }
.chooser header button { width: 2rem; padding: 0.2rem 0; font-size: 1.1rem; line-height: 1; }
.chooser_body {
display: flex;
gap: 1rem;
height: calc(100% - 4rem);
margin-top: 0.75rem;
}
.chooser_notebooks {
display: flex;
flex-direction: column;
gap: 0.3rem;
width: 12rem;
overflow: auto;
}
.chooser_notebooks button { text-align: left; }
.chooser_pages {
display: grid;
flex: 1;
grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
gap: 0.75rem;
align-content: start;
overflow: auto;
}
.page_card {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.4rem;
padding: 0.5rem;
}
.page_card img {
width: 100%;
aspect-ratio: 210 / 297;
object-fit: contain;
background: var(--desk);
}
.page_card span { font-size: 0.8rem; }
/* The file chooser */
#file_chooser[open] { display: flex; flex-direction: column; }
.files_place, .files_save {
display: flex;
gap: 0.5rem;
margin-top: 0.75rem;
}
.files_place input, .files_save input { flex: 1; min-width: 0; }
/* Directories down the left, one to a line; the files beside them. Each
scrolls by itself, as in the notebook chooser. */
.files_body {
display: flex;
flex: 1;
gap: 1rem;
min-height: 0;
margin-top: 0.75rem;
}
.files_directories {
display: flex;
flex: none;
flex-direction: column;
gap: 0.3rem;
width: 12rem;
overflow: auto;
}
.files_directories button { text-align: left; overflow-wrap: anywhere; }
.files_entries {
flex: 1;
overflow: auto;
}
.files_existing {
display: flex;
flex-wrap: wrap;
gap: 0.3rem;
}
.files_images {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
gap: 0.75rem;
align-content: start;
}
.file_card {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.4rem;
padding: 0.5rem;
}
.file_card canvas {
width: 100%;
aspect-ratio: 4 / 3;
object-fit: contain;
background: var(--desk);
}
.file_card span { font-size: 0.8rem; overflow-wrap: anywhere; }
.tooltip {
position: fixed;
z-index: 10;
max-width: 20rem;
padding: 0.4rem 0.6rem;
border-radius: 6px;
background: var(--ink);
color: white;
font-size: 0.85rem;
line-height: 1.35;
box-shadow: 0 2px 8px rgb(0 0 0 / 0.25);
pointer-events: none;
}
.report {
margin-top: 1.5rem;
font-size: 0.8rem;
color: var(--muted);
font-variant-numeric: tabular-nums;
}