/* arla-auth additions.

   Everything structural — cards, fields, buttons, the toast — comes from
   arla-style.css, shared verbatim with the node admin panel. Only what
   the control plane has and the node doesn't lives here. */

/* ---- sign in ---- */

/* Signing in is the entire page, so it sits in the middle of the viewport
   rather than at the top of a document flow. */
.signin {
    max-width: 26rem;
    margin: 4rem auto;
    text-align: center;
}

.signin h1 {
    margin-bottom: 0.5rem;
}

.signin .tagline {
    margin-bottom: 2rem;
}

.provider-list {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    margin-bottom: 2rem;
}

/* Provider buttons read as one stack of equal choices — no "primary"
   among them, because which one you use is not our preference to have. */
.provider-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    width: 100%;
    padding: 0.75rem 1.5rem;
    border-radius: var(--pill-radius);
    border: var(--field-border) solid var(--border);
    background-color: var(--bg-primary);
    color: var(--text-primary);
    font-size: 1rem;
    font-weight: 600;
    text-decoration: none;
    transition: border-color 0.15s, box-shadow 0.15s;
}

.provider-btn:hover {
    border-color: var(--primary);
    box-shadow: 0 4px 12px var(--shadow-color);
    text-decoration: none;
}

.provider-mark {
    width: 1.25rem;
    height: 1.25rem;
    flex-shrink: 0;
}

.signin-note {
    font-size: 0.85rem;
    color: var(--text-muted);
}

/* The provider stack ends with margin-bottom: 2rem, so the divider only
   needs to separate itself from what follows. */
.signin-divider {
    margin: -1rem 0 1rem;
    font-size: 0.85rem;
    color: var(--text-muted);
}

/* Below the OAuth buttons and visibly secondary to them: most customers
   have a Google or GitHub account, and the ones who don't are the reason
   this exists. */
.magic-form {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-bottom: 2rem;
    text-align: left;
}

.magic-form label {
    font-size: 0.85rem;
    color: var(--text-muted);
}

.magic-form button {
    align-self: stretch;
}

/* ---- dashboard ---- */

/* A quieter card for the secondary action at the bottom of the page, so
   "create another org" doesn't compete with the bots above it. */
.card-quiet {
    background-color: transparent;
    border-style: dashed;
}

/* A bot row is the node's document row: same surface, same height, same
   trailing icon buttons. Structure copied from `.document-list` /
   `.document-item` in arla-style.css rather than reusing those class names,
   which the shared sheet owns and which mean "document" over there. */
.bot-list {
    list-style: none;
    margin: 0 0 1.25rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.bot-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    min-height: 3.75rem;
    padding: 0.5rem 0.75rem;
    background-color: var(--bg-primary);
    border: 1px solid var(--border);
    border-radius: var(--field-radius);
    transition: border-color 0.15s;
}

.bot-row:hover {
    border-color: var(--text-muted);
}

.bot-row.empty {
    justify-content: center;
    color: var(--text-muted);
    border-style: dashed;
}

.bot-row.empty:hover {
    border-color: var(--border);
}

/* The add affordance is a row rather than a field sitting in the page, so
   the whole line is the target and nothing is asking to be filled in until
   you say so — the node's `.document-upload`, with the plus row moved
   to the bottom because here it follows the bots you have rather than
   introducing them. Also used for "new org" under the last card. */
.add-row {
    padding: 0;
    border-style: dashed;
}

.add-row-btn {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
    min-height: 3.6rem;
    padding: 0.5rem 0.75rem;
    background: none;
    border: none;
    border-radius: var(--field-radius);
    color: var(--primary);
    font-weight: 600;
    text-align: left;
    cursor: pointer;
}

.add-row-btn:hover {
    background-color: color-mix(in srgb, var(--primary) 10%, transparent);
    filter: none;
    box-shadow: none;
}

/* The org one is a link to a real form, not a prompt, so it needs
   the anchor reset that the button gets for free. */
a.add-row-btn,
a.add-row-btn:hover {
    text-decoration: none;
}

/* Standalone — an org row sits under the cards rather than inside a
   list, so it carries the row's own surface and spacing. */
.add-row-standalone {
    list-style: none;
    margin: 0;
    padding: 0;
    border: 1px solid var(--border);
    border-style: dashed;
    border-radius: var(--field-radius);
    background-color: var(--bg-primary);
    transition: border-color 0.15s;
}

.add-row-standalone:hover {
    border-color: var(--text-muted);
}

.bot-id {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1;
}

.bot-id a {
    font-weight: 600;
}

/* The hostname is the thing customers actually paste into DNS and support
   tickets, so it's monospace and selectable rather than decorative. */
.bot-host {
    font-family: "SF Mono", Menlo, Monaco, Consolas, ui-monospace, monospace;
    font-size: 0.8rem;
    color: var(--text-muted);
    overflow-wrap: anywhere;
}

/* One pill, two lists: a bot's status and a person's grants sit in the
   same place on the same kind of row. Tinted as .icon-btn-edit's hover is,
   same primary and same percentage. Only the states below, which mean
   something other than "fine", depart from it. */
.bot-status,
.perm-tag {
    flex-shrink: 0;
    font-size: 0.75rem;
    font-weight: 600;
    padding: 0.2rem 0.7rem;
    border-radius: var(--pill-radius);
    background-color: color-mix(in srgb, var(--primary) 14%, transparent);
    color: var(--primary);
}

.status-live {
    background-color: color-mix(in srgb, var(--success) 14%, transparent);
    color: var(--success);
}

/* Label stays ink: --warning against its own 14% is too pale to read. */
.status-provisioning {
    background-color: color-mix(in srgb, var(--warning) 14%, transparent);
    color: var(--text-primary);
}

/* Not an error state — a node we couldn't reach may be serving visitors
   perfectly well. Muted rather than red, so it reads as "unknown". */
.status-down {
    background-color: var(--bg-tertiary);
    color: var(--text-muted);
}

/* ---- row anatomy: bots and people alike ---- */

/* Two columns: a wide one stacking what the row says, a narrow one
   holding the buttons. Each line inside wraps on its own, so a small
   screen costs height rather than width. */
.row-main {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    flex: 1;
    /* A floor, not zero: at zero this column absorbs every pixel of
       shrink and the buttons never give up any. At min-content the shrink
       moves on to them, which is when they stack. */
    min-width: min-content;
}

/* Identity on one wrapping line: name, the grey machine-readable half,
   then whatever pill states the row. */
.row-main .bot-id,
.bot-row-open .bot-id {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0 0.6rem;
}

/* Flush: an icon button is mostly hit area already, so a gap between two
   of them is a gap between two gaps.

   The cell narrows to one button and the icons stack inside it rather
   than reserving both widths at every size. .icon-btn doesn't shrink, so
   the arrangement changes and the target never does. */
.row-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    align-items: center;
    min-width: 2.7rem;
}

/* What someone holds. Same pill as a bot's status, always neutral: these
   are facts about a person, not a state to react to. */
.perm-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}

/* Staff: admin grants reach every org, not just this one. The page's own
   two colors reversed — ink for the surface, surface for the ink. */
.perm-tag-admin {
    background-color: var(--text-primary);
    color: var(--bg-primary);
}

/* A state, not an absence — but without the surface that would imply
   something was given. */
.perm-tag-none {
    padding-left: 0;
    background: none;
    font-weight: 400;
    color: var(--text-muted);
}

/* Identity on top, boxes under it: four labelled checkboxes never fit
   beside a name on a phone. */
.bot-row-open {
    flex-direction: column;
    align-items: stretch;
    gap: 0.75rem;
    padding: 0.75rem;
}

.perm-edit {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem 1.5rem;
}

/* Also the invite form's, where it stacks with a field above and a submit
   below — hence the margin, which the open row cancels. */
.perm-set {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1.25rem;
    margin: 0.5rem 0 1.25rem;
}

.perm-edit .perm-set {
    margin: 0;
}

.perm-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-left: auto;
}

/* The invite row opened: address on its own line, then the boxes and
   buttons an open member row carries. The node row in html/nodes_list.du
   opens the same way and shares this — one field per line, then the
   controls — so the two lists open alike. */
.invite-form {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

/* Inputs carry a bottom margin for stacked forms; it would double the
   column's gap here. */
.invite-form input[type="email"],
.invite-form input[type="text"],
.invite-form input[type="number"],
.invite-form .form-error {
    margin: 0;
}

/* What the link is, beside the field that sends it. */
.invite-hint {
    margin: 0;
    font-size: 0.85rem;
}

/* ---- one bot ---- */

.crumb {
    margin: 0 0 1rem;
    font-size: 0.9rem;
}

.bot-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.25rem;
}

/* The status pill rides with the title. It describes the bot, not the tab
   you happen to be on, so it belongs above the tab bar and is rendered
   once by the frame both tabs share. */
.bot-header h1 {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    margin: 0 0 0.25rem;
}

/* Names the period for everything below it, so it sits on the page above
   the cards rather than inside any one of them. The picker sits opposite
   the heading it changes. */
.period-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.25rem;
}

.range-picker select {
    margin-bottom: 0;
    width: auto;
}

/* Reachable by a screen reader, invisible on screen — the select's
   purpose is obvious next to the heading, but it still needs a name. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.period-head h2 {
    margin: 0 0 0.15rem;
    font-size: 1.25rem;
}

.period-head p {
    margin: 0;
    font-size: 0.9rem;
}

/* An anchor that has to sit next to the icon and read as a button. */
.button-link {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    flex-shrink: 0;
    padding: 0.6rem 1.1rem;
    border: var(--field-border) solid var(--border);
    border-radius: var(--field-radius);
    color: var(--text-primary);
    font-weight: 600;
    text-decoration: none;
}

.button-link:hover {
    border-color: var(--primary);
    color: var(--primary);
    text-decoration: none;
}

/* Label above value, wrapping into as many columns as fit. Reads down the
   page on a phone without a media query. */
.fact-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: 1.25rem;
    margin: 0;
}

.fact dt {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    margin-bottom: 0.25rem;
}

.fact dd {
    margin: 0;
    overflow-wrap: anywhere;
}

.fact-hint {
    display: block;
    font-size: 0.8rem;
    color: var(--text-muted);
}

.ok-note {
    color: var(--success);
}

.warn-note {
    color: var(--error);
}

.node-down {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
}

.node-down .doc-icon {
    flex-shrink: 0;
    color: var(--text-muted);
}

.down-reason {
    margin: 0 0 0.5rem;
    font-weight: 600;
}

.node-down p {
    max-width: 52ch;
}

.node-down button {
    margin-top: 1rem;
}

/* ---- bot tabs ---- */

.tab-bar {
    display: flex;
    gap: 0.25rem;
    margin-bottom: 1.25rem;
    border-bottom: 1px solid var(--border);
}

.tab {
    padding: 0.6rem 1rem;
    color: var(--text-muted);
    font-weight: 600;
    text-decoration: none;
    /* Transparent rather than absent, so the tab doesn't shift by 2px
       when it becomes current. */
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}

.tab:hover {
    color: var(--text-primary);
    text-decoration: none;
}

.tab[aria-current="page"] {
    color: var(--primary);
    border-bottom-color: var(--primary);
}

/* ---- analytics ---- */

/* Four across, then two, then one. Explicit breakpoints rather than
   auto-fit: a sparkline needs a sensible minimum width to read as a
   shape, and auto-fit will happily give it less. */
.kpi-row {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 1rem;
    margin-bottom: 1rem;
}

@media (max-width: 60rem) {
    .kpi-row {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 30rem) {
    .kpi-row {
        grid-template-columns: 1fr;
    }
}

/* Each tile is its own card, so it carries the card's own margin rules
   rather than the stacked-section spacing. */
.stat-tile {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    margin-bottom: 0;
}

.tile-label {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
}

/* Proportional figures, not tabular: these are standalone display numbers,
   and tabular-nums makes them look loose at this size. The table below
   uses tabular, where digits do have to line up. */
.tile-value {
    font-size: 1.75rem;
    font-weight: 600;
    line-height: 1.1;
    color: var(--text-primary);
}

.tile-hint {
    font-size: 0.78rem;
    color: var(--text-muted);
}

.chart-title {
    font-size: 0.95rem;
    margin: 0 0 0.75rem;
}



/* ---- svgraph ----
   Copied from the node's dashboard.css so the two products draw the
   same charts. svgraph emits sg- classes on everything and can skip its
   own background, so color and weight are CSS here rather than anything
   lib/chart.du does to the markup. Keep these in step with the node. */

.sg-axis,
.sg-tick,
.sg-leader {
    stroke: var(--border);
}

.sg-title,
.sg-tick-label,
.sg-axis-label,
.sg-label {
    fill: var(--text-muted);
}

/* Matches the bare "sg-series" token on lines only — donut slices carry
   sg-series-0, sg-series-1 … and keep svgraph's own palette. */
.sg-series {
    stroke: var(--primary);
}

.sg-area,
.sg-point {
    fill: var(--primary);
}

/* svgraph fills bars from its palette by index, which is right when each
   bar is a different thing and wrong here — these are one metric across
   thirty days. A CSS rule beats the fill attribute, so one hue wins. */
.sg-bar {
    fill: var(--primary);
}

.sg-leader-dot {
    fill: var(--border);
    stroke: var(--border);
}

/* No height here on purpose: the canvas in lib/chart.du sets the shape,
   and height:auto lets the viewBox's own ratio follow it. Declaring a
   height in both places is what produces letterboxing. */
.chart-frame svg {
    display: block;
    width: 100%;
    height: auto;
}

/* The donut is the content of its card, not an inset thumbnail. At 20rem
   its labels were rendering around 8px; full width they land near 17px,
   because svgraph sizes type in user units on a 1200-wide canvas. */
.chart-frame-wide {
    width: 100%;
    margin-bottom: 1.25rem;
}

/* Hover feedback with no script: svgraph puts a class on every mark and a
   <title> child inside it for the browser's own tooltip.

   The hovered mark lights up; nothing else changes. Dimming the other
   slices reads as the whole chart reacting to the pointer, which is
   distracting when you're just moving across it. The glow is built from
   --text-primary so it inverts with the theme instead of needing a color
   per slice. */
.sg-slice,
.sg-bar {
    transition: filter 0.15s;
}

.sg-slice:hover,
.sg-bar:hover {
    filter:
        brightness(1.12)
        drop-shadow(0 0 5px color-mix(in srgb, var(--text-primary) 35%, transparent));
}

/* --- tile sparklines --- */

.spark {
    display: block;
    margin-top: 0.6rem;
    opacity: 0.75;
}

.spark svg {
    display: block;
    width: 100%;
    height: auto;
}

/* The canvas is 240x40 but the tile is whatever the grid gives it, so
   without this the stroke thins and thickens with the column width. */
.spark .sg-series {
    vector-effect: non-scaling-stroke;
}

/* --- device split --- */

/* The numbers sit under the donut, in the same card, so identity never
   rests on slice color alone. */
.device-facts {
    border-top: 1px solid var(--border);
    padding-top: 1.25rem;
}

/* Monospace so the mask's dots line up and the tail is easy to compare
   against what the node's own settings field shows. */
.key-mask {
    font-family: "SF Mono", Menlo, Monaco, Consolas, ui-monospace, monospace;
    font-size: 0.85rem;
    overflow-wrap: anywhere;
}

/* The pencil sits against the org name, not out at the card edge,
   so it reads as belonging to the heading rather than to the card. */
.card-head h2 {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

/* Rename is the same affordance as delete, one step less final, so it gets
   .icon-btn-danger's rule with --primary in place of --error: same tint
   percentage, same pair of properties, nothing invented. This belongs in
   arla-style.css alongside .icon-btn-danger the moment the node grows
   an edit button — it is a shared standard, not a control-plane rule. */
.icon-btn-edit:hover {
    background-color: color-mix(in srgb, var(--primary) 12%, transparent);
    color: var(--primary);
}

/* Field and button on one line, wrapping together on a phone. The shared
   input rule carries a 1rem bottom margin for stacked forms, which would
   knock these out of alignment. */
.inline-form {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
}

.inline-form input[type="text"] {
    flex: 1;
    min-width: 12rem;
    margin-bottom: 0;
}

.inline-form button {
    flex-shrink: 0;
}

/* ---- interstitials ---- */

/* Handoff failures (unknown bot, not your bot) get a real page rather
   than a JSON error — the customer arrived here by clicking a link, and
   needs a way back, not a status code. */
.interstitial {
    max-width: 32rem;
    margin: 4rem auto;
    text-align: center;
}

.interstitial p {
    color: var(--text-secondary);
    margin-bottom: 2rem;
}

/* ---- billing ---- */

/* The node has no phone field, so arla-style.css — which is copied
   from it verbatim — styles every input type except tel. Rather than
   diverge the shared file, the one type only this server uses is pulled
   into the same rules here. Keep the values in step with the
   input[type="text"] block in arla-style.css. */
input[type="tel"] {
    width: 100%;
    height: var(--field-height);
    padding: var(--field-pad-y) 0.75rem;
    border: var(--field-border) solid var(--border);
    border-radius: var(--field-radius);
    background-color: var(--bg-primary);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 1rem;
    line-height: var(--field-line);
    margin-bottom: 1rem;
    transition: border-color 0.2s, box-shadow 0.2s;
}

input[type="tel"]:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px var(--primary-lighter);
}

/* Confirmation after a successful save, and the note explaining that
   billing is switched off on this server. Neither is an error. */
.form-note {
    color: var(--text-secondary);
    background: var(--bg-secondary);
    border-radius: var(--field-radius);
    padding: 0.75rem 1rem;
    margin-bottom: 1rem;
}

/* Splits the staff editor's two halves: what you may do to a customer's
   bots, and what you may do to the platform. */
.staff-divider {
    width: 100%;
    margin: 0;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
